diff --git a/controllers/integrationpipeline/integrationpipeline_adapter.go b/controllers/integrationpipeline/integrationpipeline_adapter.go
index 8fcee8169..bed404191 100644
--- a/controllers/integrationpipeline/integrationpipeline_adapter.go
+++ b/controllers/integrationpipeline/integrationpipeline_adapter.go
@@ -61,24 +61,6 @@ func NewAdapter(pipelineRun *tektonv1beta1.PipelineRun, component *applicationap
}
}
-// EnsureStatusReported will ensure that integration PipelineRun status is reported to the git provider
-// which (indirectly) triggered its execution.
-func (a *Adapter) EnsureStatusReported() (controller.OperationResult, error) {
- reporters, err := a.status.GetReporters(a.pipelineRun)
-
- if err != nil {
- return controller.RequeueWithError(err)
- }
-
- for _, reporter := range reporters {
- if err := reporter.ReportStatus(a.client, a.context, a.pipelineRun); err != nil {
- return controller.RequeueWithError(err)
- }
- }
-
- return controller.ContinueProcessing()
-}
-
// EnsureStatusReportedInSnapshot will ensure that status of the integration test pipelines is reported to snapshot
// to be consumed by user
func (a *Adapter) EnsureStatusReportedInSnapshot() (controller.OperationResult, error) {
diff --git a/controllers/integrationpipeline/integrationpipeline_adapter_test.go b/controllers/integrationpipeline/integrationpipeline_adapter_test.go
index f18cc663d..f8379fb51 100644
--- a/controllers/integrationpipeline/integrationpipeline_adapter_test.go
+++ b/controllers/integrationpipeline/integrationpipeline_adapter_test.go
@@ -18,8 +18,6 @@ package integrationpipeline
import (
"bytes"
- "context"
- "errors"
"reflect"
"time"
@@ -39,44 +37,15 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"
- "github.com/redhat-appstudio/integration-service/status"
tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tonglil/buflogr"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
)
-type MockStatusAdapter struct {
- Reporter *MockStatusReporter
- GetReportersError error
-}
-
-type MockStatusReporter struct {
- Called bool
- ReportStatusError error
-}
-
-func (r *MockStatusReporter) ReportStatus(client.Client, context.Context, *tektonv1beta1.PipelineRun) error {
- r.Called = true
- return r.ReportStatusError
-}
-
-func (r *MockStatusReporter) ReportStatusForSnapshot(client.Client, context.Context, *helpers.IntegrationLogger, *applicationapiv1alpha1.Snapshot) error {
- r.Called = true
- return r.ReportStatusError
-}
-
-func (a *MockStatusAdapter) GetReporters(object client.Object) ([]status.Reporter, error) {
- return []status.Reporter{a.Reporter}, a.GetReportersError
-}
-
var _ = Describe("Pipeline Adapter", Ordered, func() {
var (
- adapter *Adapter
- createAdapter func() *Adapter
- logger helpers.IntegrationLogger
- statusAdapter *MockStatusAdapter
- statusReporter *MockStatusReporter
+ adapter *Adapter
+ logger helpers.IntegrationLogger
successfulTaskRun *tektonv1beta1.TaskRun
failedTaskRun *tektonv1beta1.TaskRun
@@ -593,98 +562,6 @@ var _ = Describe("Pipeline Adapter", Ordered, func() {
})
- When("EnsureStatusReported is called", func() {
- It("ensures status is reported for integration PipelineRuns", func() {
- adapter = createAdapter()
- adapter.context = loader.GetMockedContext(ctx, []loader.MockData{
- {
- ContextKey: loader.ApplicationContextKey,
- Resource: hasApp,
- },
- {
- ContextKey: loader.ComponentContextKey,
- Resource: hasComp,
- },
- {
- ContextKey: loader.SnapshotContextKey,
- Resource: hasSnapshot,
- },
- {
- ContextKey: loader.TaskRunContextKey,
- Resource: successfulTaskRun,
- },
- {
- ContextKey: loader.EnvironmentContextKey,
- Resource: hasEnv,
- },
- {
- ContextKey: loader.PipelineRunsContextKey,
- Resource: []tektonv1beta1.PipelineRun{*integrationPipelineRunComponent},
- },
- {
- ContextKey: loader.RequiredIntegrationTestScenariosContextKey,
- Resource: []v1beta1.IntegrationTestScenario{*integrationTestScenario},
- },
- })
-
- adapter.pipelineRun = &tektonv1beta1.PipelineRun{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pipelinerun-status-sample",
- Namespace: "default",
- Labels: map[string]string{
- "appstudio.openshift.io/application": "test-application",
- "appstudio.openshift.io/component": "devfile-sample-go-basic",
- "appstudio.openshift.io/snapshot": "test-application-s8tnj",
- "test.appstudio.openshift.io/scenario": "example-pass",
- "pac.test.appstudio.openshift.io/state": "started",
- "pac.test.appstudio.openshift.io/sender": "foo",
- "pac.test.appstudio.openshift.io/check-run-id": "9058825284",
- "pac.test.appstudio.openshift.io/branch": "main",
- "pac.test.appstudio.openshift.io/url-org": "devfile-sample",
- "pac.test.appstudio.openshift.io/original-prname": "devfile-sample-go-basic-on-pull-request",
- "pac.test.appstudio.openshift.io/url-repository": "devfile-sample-go-basic",
- "pac.test.appstudio.openshift.io/repository": "devfile-sample-go-basic",
- "pac.test.appstudio.openshift.io/sha": "12a4a35ccd08194595179815e4646c3a6c08bb77",
- "pac.test.appstudio.openshift.io/git-provider": "github",
- "pac.test.appstudio.openshift.io/event-type": "pull_request",
- "pipelines.appstudio.openshift.io/type": "test",
- },
- Annotations: map[string]string{
- "pac.test.appstudio.openshift.io/on-target-branch": "[main,master]",
- "pac.test.appstudio.openshift.io/repo-url": "https://github.com/devfile-samples/devfile-sample-go-basic",
- "pac.test.appstudio.openshift.io/sha-title": "Appstudio update devfile-sample-go-basic",
- "pac.test.appstudio.openshift.io/git-auth-secret": "pac-gitauth-zjib",
- "pac.test.appstudio.openshift.io/pull-request": "16",
- "pac.test.appstudio.openshift.io/on-event": "[pull_request]",
- "pac.test.appstudio.openshift.io/installation-id": "30353543",
- },
- },
- Spec: tektonv1beta1.PipelineRunSpec{
- PipelineRef: &tektonv1beta1.PipelineRef{
- Name: "component-pipeline-pass",
- Bundle: "quay.io/kpavic/test-bundle:component-pipeline-pass",
- },
- },
- }
-
- result, err := adapter.EnsureStatusReported()
- Expect(!result.CancelRequest && err == nil).To(BeTrue())
-
- Expect(statusReporter.Called).To(BeTrue())
-
- statusAdapter.GetReportersError = errors.New("GetReportersError")
-
- result, err = adapter.EnsureStatusReported()
- Expect(result.RequeueRequest && err != nil && err.Error() == "GetReportersError").To(BeTrue())
-
- statusAdapter.GetReportersError = nil
- statusReporter.ReportStatusError = errors.New("ReportStatusError")
-
- result, err = adapter.EnsureStatusReported()
- Expect(result.RequeueRequest && err != nil && err.Error() == "ReportStatusError").To(BeTrue())
- })
- })
-
When("EnsureEphemeralEnvironmentsCleanedUp is called", func() {
BeforeEach(func() {
deploymentTargetClass = &applicationapiv1alpha1.DeploymentTargetClass{
@@ -802,11 +679,4 @@ var _ = Describe("Pipeline Adapter", Ordered, func() {
})
})
- createAdapter = func() *Adapter {
- adapter = NewAdapter(integrationPipelineRunComponent, hasComp, hasApp, logger, loader.NewMockLoader(), k8sClient, ctx)
- statusReporter = &MockStatusReporter{}
- statusAdapter = &MockStatusAdapter{Reporter: statusReporter}
- adapter.status = statusAdapter
- return adapter
- }
})
diff --git a/controllers/integrationpipeline/integrationpipeline_controller.go b/controllers/integrationpipeline/integrationpipeline_controller.go
index a4a10ffd5..535cc4673 100644
--- a/controllers/integrationpipeline/integrationpipeline_controller.go
+++ b/controllers/integrationpipeline/integrationpipeline_controller.go
@@ -109,14 +109,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return controller.ReconcileHandler([]controller.Operation{
adapter.EnsureStatusReportedInSnapshot,
- adapter.EnsureStatusReported,
adapter.EnsureEphemeralEnvironmentsCleanedUp,
})
}
// AdapterInterface is an interface defining all the operations that should be defined in an Integration adapter.
type AdapterInterface interface {
- EnsureStatusReported() (controller.OperationResult, error)
EnsureStatusReportedInSnapshot() (controller.OperationResult, error)
EnsureEphemeralEnvironmentsCleanedUp() (controller.OperationResult, error)
}
diff --git a/controllers/statusreport/statusreport_adapter.go b/controllers/statusreport/statusreport_adapter.go
index d29b1463d..f505a2457 100644
--- a/controllers/statusreport/statusreport_adapter.go
+++ b/controllers/statusreport/statusreport_adapter.go
@@ -23,7 +23,6 @@ import (
"github.com/redhat-appstudio/integration-service/gitops"
"github.com/redhat-appstudio/integration-service/metrics"
"github.com/redhat-appstudio/operator-toolkit/metadata"
- "os"
applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"
"github.com/redhat-appstudio/integration-service/helpers"
@@ -35,8 +34,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
-const FeatureFlagStatusReprotingEnabled = "FEATURE_STATUS_REPORTING_ENABLED"
-
// Adapter holds the objects needed to reconcile a snapshot's test status report.
type Adapter struct {
snapshot *applicationapiv1alpha1.Snapshot
@@ -62,10 +59,10 @@ func NewAdapter(snapshot *applicationapiv1alpha1.Snapshot, application *applicat
}
}
-// EnsureSnapshotTestStatusReported will ensure that integration test status including env provision and snapshotEnvironmentBinding error is reported to the git provider
+// EnsureSnapshotTestStatusReportedToGitHub will ensure that integration test status including env provision and snapshotEnvironmentBinding error is reported to the git provider
// which (indirectly) triggered its execution.
-func (a *Adapter) EnsureSnapshotTestStatusReported() (controller.OperationResult, error) {
- if !isFeatureEnabled() || !gitops.IsSnapshotCreatedByPACPullRequestEvent(a.snapshot) {
+func (a *Adapter) EnsureSnapshotTestStatusReportedToGitHub() (controller.OperationResult, error) {
+ if !gitops.IsSnapshotCreatedByPACPullRequestEvent(a.snapshot) {
return controller.ContinueProcessing()
}
@@ -85,14 +82,6 @@ func (a *Adapter) EnsureSnapshotTestStatusReported() (controller.OperationResult
return controller.ContinueProcessing()
}
-// isFeatureEnabled returns true when the feature flag FEATURE_STATUS_REPORTING_ENABLED has been defined in env vars
-func isFeatureEnabled() bool {
- if _, found := os.LookupEnv(FeatureFlagStatusReprotingEnabled); found {
- return true
- }
- return false
-}
-
// EnsureSnapshotFinishedAllTests is an operation that will ensure that a pipeline Snapshot
// to the PipelineRun being processed finished and passed all tests for all defined required IntegrationTestScenarios.
// If the Snapshot doesn't have the freshest state of components, a composite Snapshot will be created instead
diff --git a/controllers/statusreport/statusreport_adapter_test.go b/controllers/statusreport/statusreport_adapter_test.go
index e80edeb61..a38c1c4c7 100644
--- a/controllers/statusreport/statusreport_adapter_test.go
+++ b/controllers/statusreport/statusreport_adapter_test.go
@@ -23,7 +23,6 @@ import (
"github.com/redhat-appstudio/integration-service/api/v1beta1"
"github.com/tonglil/buflogr"
"k8s.io/apimachinery/pkg/api/meta"
- "os"
"reflect"
"time"
@@ -34,7 +33,6 @@ import (
"github.com/redhat-appstudio/integration-service/loader"
intgteststat "github.com/redhat-appstudio/integration-service/pkg/integrationteststatus"
"github.com/redhat-appstudio/integration-service/status"
- tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -54,11 +52,6 @@ type MockStatusReporter struct {
ReportStatusError error
}
-func (r *MockStatusReporter) ReportStatus(client.Client, context.Context, *tektonv1beta1.PipelineRun) error {
- r.Called = true
- return r.ReportStatusError
-}
-
func (r *MockStatusReporter) ReportStatusForSnapshot(client.Client, context.Context, *helpers.IntegrationLogger, *applicationapiv1alpha1.Snapshot) error {
r.Called = true
r.ReportStatusError = nil
@@ -260,10 +253,6 @@ var _ = Describe("Snapshot Adapter", Ordered, func() {
},
}
Expect(k8sClient.Create(ctx, hasSnapshot)).Should(Succeed())
-
- // enable feature flag for testing
- err := os.Setenv(FeatureFlagStatusReprotingEnabled, "yes")
- Expect(err).To(BeNil())
})
AfterEach(func() {
@@ -293,7 +282,7 @@ var _ = Describe("Snapshot Adapter", Ordered, func() {
Resource: hasPRSnapshot,
},
})
- result, err := adapter.EnsureSnapshotTestStatusReported()
+ result, err := adapter.EnsureSnapshotTestStatusReportedToGitHub()
fmt.Fprintf(GinkgoWriter, "-------err: %v\n", err)
fmt.Fprintf(GinkgoWriter, "-------result: %v\n", result)
Expect(!result.CancelRequest && err == nil).To(BeTrue())
diff --git a/controllers/statusreport/statusreport_controller.go b/controllers/statusreport/statusreport_controller.go
index 2e862cc40..e6a1b7f96 100644
--- a/controllers/statusreport/statusreport_controller.go
+++ b/controllers/statusreport/statusreport_controller.go
@@ -81,14 +81,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
adapter := NewAdapter(snapshot, application, logger, loader, r.Client, ctx)
return controller.ReconcileHandler([]controller.Operation{
- adapter.EnsureSnapshotTestStatusReported,
+ adapter.EnsureSnapshotTestStatusReportedToGitHub,
adapter.EnsureSnapshotFinishedAllTests,
})
}
// AdapterInterface is an interface defining all the operations that should be defined in an Integration adapter.
type AdapterInterface interface {
- EnsureSnapshotTestStatusReported() (controller.OperationResult, error)
+ EnsureSnapshotTestStatusReportedToGitHub() (controller.OperationResult, error)
EnsureSnapshotFinishedAllTests() (controller.OperationResult, error)
}
diff --git a/docs/statusreport-controller.md b/docs/statusreport-controller.md
index fad7b4a80..cb26b15cc 100644
--- a/docs/statusreport-controller.md
+++ b/docs/statusreport-controller.md
@@ -8,7 +8,7 @@ flowchart TD
predicate((PREDICATE:
Snapshot has annotation
test.appstudio.openshift.io/status
changed))
- %%%%%%%%%%%%%%%%%%%%%%% Drawing EnsureSnapshotTestStatusReported() function
+ %%%%%%%%%%%%%%%%%%%%%%% Drawing EnsureSnapshotTestStatusReportedToGitHub() function
%% Node definitions
ensure(Process further if: Snapshot has label
pac.test.appstudio.openshift.io/git-provider:github
defined)
@@ -30,11 +30,14 @@ flowchart TD
create_commitStatusAdapter(Create commitStatusAdapter according to
commit owner, repo, SHA
and integration test status)
does_commitStatus_exist{Does commitStatus exist
on github already?}
create_new_commitStatus_on_gh(Create new commitStatus on github)
+ does_comment_exist(Does a comment exist for snapshot and scenario?)
+ update_existing_comment(Update the existing comment for
snapshot and scenario)
+ create_new_comment(Create a new comment for
snapshot and scenario)
continue_processing(Controller continues processing)
%% Node connections
- predicate ----> |"EnsureSnapshotTestStatusReported()"|ensure
+ predicate ----> |"EnsureSnapshotTestStatusReportedToGitHub()"|ensure
ensure --> get_annotation_value
get_annotation_value --> collect_commit_info
collect_commit_info --> is_installation_defined
@@ -56,7 +59,11 @@ flowchart TD
create_commitStatusAdapter --> does_commitStatus_exist
does_commitStatus_exist --Yes--> continue_processing
does_commitStatus_exist --No--> create_new_commitStatus_on_gh
- create_new_commitStatus_on_gh --> continue_processing
+ create_new_commitStatus_on_gh --> does_comment_exist
+ does_comment_exist --Yes--> update_existing_comment
+ does_comment_exist --No--> create_new_comment
+ update_existing_comment --> continue_processing
+ create_new_comment --> continue_processing
%%%%%%%%%%%%%%%%%%%%%%% Drawing EnsureSnapshotTestStatusReported() function
diff --git a/git/github/github.go b/git/github/github.go
index 4dd11d199..21683b44e 100644
--- a/git/github/github.go
+++ b/git/github/github.go
@@ -20,6 +20,7 @@ import (
"context"
"fmt"
"net/http"
+ "strings"
"time"
"github.com/bradleyfalzon/ghinstallation/v2"
@@ -78,6 +79,8 @@ type ChecksService interface {
// IssuesService defines the methods used in the github Issues service.
type IssuesService interface {
CreateComment(ctx context.Context, owner string, repo string, number int, comment *ghapi.IssueComment) (*ghapi.IssueComment, *ghapi.Response, error)
+ ListComments(ctx context.Context, owner string, repo string, number int, opts *ghapi.IssueListCommentsOptions) ([]*ghapi.IssueComment, *ghapi.Response, error)
+ EditComment(ctx context.Context, owner string, repo string, id int64, comment *ghapi.IssueComment) (*ghapi.IssueComment, *ghapi.Response, error)
}
// RepositoriesService defines the methods used in the github Repositories service.
@@ -99,7 +102,10 @@ type ClientInterface interface {
IsUpdateNeeded(existingCheckRun *ghapi.CheckRun, newCheckRun *CheckRunAdapter) bool
GetExistingCheckRun(checkRuns []*ghapi.CheckRun, newCheckRun *CheckRunAdapter) *ghapi.CheckRun
GetAllCommitStatusesForRef(ctx context.Context, owner, repo, sha string) ([]*ghapi.RepoStatus, error)
+ GetAllCommentsForPR(ctx context.Context, owner string, repo string, pr int) ([]*ghapi.IssueComment, error)
CommitStatusExists(res []*ghapi.RepoStatus, commitStatus *CommitStatusAdapter) (bool, error)
+ GetExistingCommentID(comments []*ghapi.IssueComment, snapshotName, scenarioName string) *int64
+ EditComment(ctx context.Context, owner string, repo string, commentID int64, body string) (int64, error)
}
// Client is an abstraction around the API client.
@@ -374,6 +380,18 @@ func (c *Client) GetExistingCheckRun(checkRuns []*ghapi.CheckRun, newCheckRun *C
return nil
}
+// GetExistingComment returns existing GitHub comment for the scenario of ref.
+func (c *Client) GetExistingCommentID(comments []*ghapi.IssueComment, snapshotName, scenarioName string) *int64 {
+ for _, comment := range comments {
+ if strings.Contains(*comment.Body, snapshotName) && strings.Contains(*comment.Body, scenarioName) {
+ c.logger.Info("found comment ID with a matching scenarioName", "scenarioName", scenarioName)
+ return comment.ID
+ }
+ }
+ c.logger.Info("found no comment with a matching scenarioName", "scenarioName", scenarioName)
+ return nil
+}
+
// IsUpdateNeeded check if check run update is needed
// according to the text of existingCheckRun and newCheckRun since the details are different every update
func (c *Client) IsUpdateNeeded(existingCheckRun *ghapi.CheckRun, newCheckRun *CheckRunAdapter) bool {
@@ -403,6 +421,21 @@ func (c *Client) GetAllCommitStatusesForRef(ctx context.Context, owner, repo, sh
return res, nil
}
+// GetAllCommentsForPR returns all existing comment if a match for the Owner, Repo, and PR.
+func (c *Client) GetAllCommentsForPR(ctx context.Context, owner string, repo string, number int) ([]*ghapi.IssueComment, error) {
+ res, _, err := c.GetIssuesService().ListComments(ctx, owner, repo, number, &ghapi.IssueListCommentsOptions{})
+ if err != nil {
+ return nil, fmt.Errorf("failed to get all comments for GitHub owner/repo/PR %s/%s/%d: %w", owner, repo, number, err)
+ }
+
+ if len(res) == 0 {
+ c.logger.Info("Found no comments for PR", "PR", number)
+ return nil, nil
+ }
+
+ return res, nil
+}
+
// CommitStatusExists returns if a match is found for the SHA, state, context and decription.
func (c *Client) CommitStatusExists(res []*ghapi.RepoStatus, commitStatus *CommitStatusAdapter) (bool, error) {
for _, cs := range res {
@@ -422,7 +455,7 @@ func (c *Client) CommitStatusExists(res []*ghapi.RepoStatus, commitStatus *Commi
func (c *Client) CreateComment(ctx context.Context, owner string, repo string, issueNumber int, body string) (int64, error) {
comment, _, err := c.GetIssuesService().CreateComment(ctx, owner, repo, issueNumber, &ghapi.IssueComment{Body: &body})
if err != nil {
- return 0, err
+ return 0, fmt.Errorf("failed to create a comment for GitHub owner/repo/PR %s/%s/%d: %w", owner, repo, issueNumber, err)
}
c.logger.Info("Created comment",
@@ -434,11 +467,27 @@ func (c *Client) CreateComment(ctx context.Context, owner string, repo string, i
return *comment.ID, nil
}
+// EditComment edits an existing issue comment via the GitHub API.
+func (c *Client) EditComment(ctx context.Context, owner string, repo string, commentID int64, body string) (int64, error) {
+ comment, _, err := c.GetIssuesService().EditComment(ctx, owner, repo, commentID, &ghapi.IssueComment{Body: &body})
+ if err != nil {
+ return 0, fmt.Errorf("failed to edit an existing comment for GitHub owner/repo/comment %s/%s/%d: %w", owner, repo, commentID, err)
+ }
+
+ c.logger.Info("Edited comment",
+ "ID", comment.ID,
+ "Owner", owner,
+ "Repository", repo,
+ "commentID", commentID,
+ )
+ return *comment.ID, nil
+}
+
// CreateCommitStatus creates a repository commit status via the GitHub API.
func (c *Client) CreateCommitStatus(ctx context.Context, owner string, repo string, SHA string, state string, description string, statusContext string) (int64, error) {
status, _, err := c.GetRepositoriesService().CreateStatus(ctx, owner, repo, SHA, &ghapi.RepoStatus{State: &state, Description: &description, Context: &statusContext})
if err != nil {
- return 0, err
+ return 0, fmt.Errorf("failed to create an existing commitStatus for GitHub owner/repo/ref %s/%s/%s: %w", owner, repo, SHA, err)
}
c.logger.Info("Created commit status",
diff --git a/git/github/github_test.go b/git/github/github_test.go
index b47b252f8..bc61e3cd7 100644
--- a/git/github/github_test.go
+++ b/git/github/github_test.go
@@ -110,6 +110,21 @@ func (MockIssuesService) CreateComment(
return &ghapi.IssueComment{ID: &id}, nil, nil
}
+// ListComments implements github.IssuesService
+func (MockIssuesService) ListComments(ctx context.Context, owner string, repo string,
+ number int, opts *ghapi.IssueListCommentsOptions) ([]*ghapi.IssueComment, *ghapi.Response, error) {
+ var id int64 = 40
+ var body string = "Integration test for snapshot snapshotName and scenario scenarioName"
+ issueComments := []*ghapi.IssueComment{{ID: &id, Body: &body}}
+ return issueComments, nil, nil
+}
+
+// EditComment implements github.IssuesService
+func (MockIssuesService) EditComment(ctx context.Context, owner string, repo string, number int64, comment *ghapi.IssueComment,
+) (*ghapi.IssueComment, *ghapi.Response, error) {
+ return &ghapi.IssueComment{ID: &number}, nil, nil
+}
+
type MockRepositoriesService struct{}
// CreateStatus implements github.RepositoriesService
@@ -309,4 +324,19 @@ var _ = Describe("Client", func() {
Expect(commitStatusExist).To(BeFalse())
Expect(err).To(BeNil())
})
+
+ It("can get existing comment id", func() {
+ comments, err := client.GetAllCommentsForPR(context.TODO(), "", "", 1)
+ Expect(err).To(BeNil())
+ Expect(len(comments) > 0).To(BeTrue())
+
+ commentID := client.GetExistingCommentID(comments, "snapshotName", "scenarioName")
+ Expect(*commentID).To(Equal(int64(40)))
+ })
+
+ It("can edit comments", func() {
+ id, err := client.EditComment(context.TODO(), "", "", 1, "example-comment")
+ Expect(err).To(BeNil())
+ Expect(id).To(Equal(int64(1)))
+ })
})
diff --git a/status/format.go b/status/format.go
index 356e741a8..1ec6981d6 100644
--- a/status/format.go
+++ b/status/format.go
@@ -66,8 +66,8 @@ func FormatSummary(taskRuns []*helpers.TaskRun) (string, error) {
return buf.String(), nil
}
-// FormatComment builds a markdown comment for a list of integration TaskRuns.
-func FormatComment(title string, results []*helpers.TaskRun) (string, error) {
+// FormatCommentForFinishedPipelineRun builds a markdown comment for a list of finished integration TaskRuns
+func FormatCommentForFinishedPipelineRun(title string, results []*helpers.TaskRun) (string, error) {
summary, err := FormatSummary(results)
if err != nil {
return "", err
@@ -82,6 +82,17 @@ func FormatComment(title string, results []*helpers.TaskRun) (string, error) {
return buf.String(), nil
}
+// FormatCommentForDetail build a markdown comment for the details of unfinished integrationTest
+func FormatCommentForDetail(title, detail string) (string, error) {
+ buf := bytes.Buffer{}
+ data := CommentTemplateData{Title: title, Summary: detail}
+ t := template.Must(template.New("").Parse(commentTemplate))
+ if err := t.Execute(&buf, data); err != nil {
+ return "", err
+ }
+ return buf.String(), nil
+}
+
// FormatStatus accepts a TaskRun and returns a Markdown friendly representation of its overall status, if any.
func FormatStatus(taskRun *helpers.TaskRun) (string, error) {
result, err := taskRun.GetTestResult()
diff --git a/status/format_test.go b/status/format_test.go
index 47bb370ab..25d8c893a 100644
--- a/status/format_test.go
+++ b/status/format_test.go
@@ -147,7 +147,7 @@ var _ = Describe("Formatters", func() {
})
It("can construct a comment", func() {
- comment, err := status.FormatComment("example-title", taskRuns)
+ comment, err := status.FormatCommentForFinishedPipelineRun("example-title", taskRuns)
Expect(err).To(BeNil())
Expect(comment).To(ContainSubstring("### example-title"))
Expect(comment).To(ContainSubstring(expectedSummary))
diff --git a/status/reporters.go b/status/reporters.go
index 398a6dd65..f1d75fd81 100644
--- a/status/reporters.go
+++ b/status/reporters.go
@@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"strconv"
- "time"
"github.com/go-logr/logr"
pacv1alpha1 "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
@@ -35,11 +34,10 @@ import (
tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
- "knative.dev/pkg/apis"
"sigs.k8s.io/controller-runtime/pkg/client"
)
-// GitHubReporter reports status back to GitHub for a PipelineRun.
+// GitHubReporter reports status back to GitHub for a Snapshot.
type GitHubReporter struct {
logger logr.Logger
k8sClient client.Client
@@ -157,98 +155,10 @@ func (r *GitHubReporter) getToken(ctx context.Context, object client.Object, nam
return string(token), nil
}
-func (r *GitHubReporter) createCheckRunAdapter(k8sClient client.Client, ctx context.Context, pipelineRun *tektonv1beta1.PipelineRun) (*github.CheckRunAdapter, error) {
- labels := pipelineRun.GetLabels()
-
- scenario, found := labels[gitops.SnapshotTestScenarioLabel]
- if !found {
- return nil, fmt.Errorf("PipelineRun label not found %q", gitops.SnapshotTestScenarioLabel)
- }
-
- component, found := labels[gitops.SnapshotComponentLabel]
- if !found {
- return nil, fmt.Errorf("PipelineRun label not found %q", gitops.SnapshotComponentLabel)
- }
-
- owner, found := labels[gitops.PipelineAsCodeURLOrgLabel]
- if !found {
- return nil, fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLOrgLabel)
- }
-
- repo, found := labels[gitops.PipelineAsCodeURLRepositoryLabel]
- if !found {
- return nil, fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLRepositoryLabel)
- }
-
- SHA, found := labels[gitops.PipelineAsCodeSHALabel]
- if !found {
- return nil, fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeSHALabel)
- }
-
- var title, conclusion string
- succeeded := pipelineRun.Status.GetCondition(apis.ConditionSucceeded)
-
- if succeeded.IsUnknown() {
- title = scenario + " has started"
- } else {
- outcome, err := helpers.GetIntegrationPipelineRunOutcome(k8sClient, ctx, pipelineRun)
-
- if err != nil {
- return nil, err
- }
-
- if outcome.HasPipelineRunPassedTesting() {
- title = scenario + " has succeeded"
- conclusion = "success"
- } else {
- title = scenario + " has failed"
- conclusion = "failure"
- }
- }
-
- taskRuns, err := helpers.GetAllChildTaskRunsForPipelineRun(r.k8sClient, ctx, pipelineRun)
- if err != nil {
- return nil, fmt.Errorf("error while getting all child taskRuns from pipelineRun %s: %w", pipelineRun.Name, err)
- }
- summary, err := FormatSummary(taskRuns)
- if err != nil {
- return nil, err
- }
-
- startTime := time.Time{}
- if start := pipelineRun.Status.StartTime; start != nil {
- startTime = start.Time
- }
-
- completionTime := time.Time{}
- if complete := pipelineRun.Status.CompletionTime; complete != nil {
- completionTime = complete.Time
- }
-
- text := ""
- if !succeeded.IsUnknown() {
- text = succeeded.Message
- }
-
- return &github.CheckRunAdapter{
- Owner: owner,
- Repository: repo,
- Name: NamePrefix + " / " + component + " / " + scenario,
- SHA: SHA,
- ExternalID: pipelineRun.Name,
- Conclusion: conclusion,
- Title: title,
- Summary: summary,
- Text: text,
- StartTime: startTime,
- CompletionTime: completionTime,
- }, nil
-}
-
-// generateSummary generate a string for the given state, snapshotName and scenarioName
+// generateSummary generate a summary used in checkRun and commitStatus
+// for the given state, snapshotName and scenarioName
func generateSummary(state intgteststat.IntegrationTestStatus, snapshotName, scenarioName string) (string, error) {
- var title string
-
+ var summary string
var statusDesc string = "is unknown"
switch state {
@@ -265,16 +175,68 @@ func generateSummary(state intgteststat.IntegrationTestStatus, snapshotName, sce
case intgteststat.IntegrationTestStatusTestFail:
statusDesc = "has failed"
default:
- return title, fmt.Errorf("unknown status")
+ return summary, fmt.Errorf("unknown status")
}
- title = fmt.Sprintf("Integration test for snapshot %s and scenario %s %s", snapshotName, scenarioName, statusDesc)
+ summary = fmt.Sprintf("Integration test for snapshot %s and scenario %s %s", snapshotName, scenarioName, statusDesc)
+
+ return summary, nil
+}
+
+// generateTitle generate a Title of checkRun for the given state
+func generateCheckRunTitle(state intgteststat.IntegrationTestStatus) (string, error) {
+ var title string
+
+ switch state {
+ case intgteststat.IntegrationTestStatusPending:
+ title = "Pending"
+ case intgteststat.IntegrationTestStatusInProgress:
+ title = "In Progress"
+ case intgteststat.IntegrationTestStatusEnvironmentProvisionError:
+ title = "Errored"
+ case intgteststat.IntegrationTestStatusDeploymentError:
+ title = "Errored"
+ case intgteststat.IntegrationTestStatusTestPassed:
+ title = "Succeeded"
+ case intgteststat.IntegrationTestStatusTestFail:
+ title = "Failed"
+ default:
+ return title, fmt.Errorf("unknown status")
+ }
return title, nil
}
+// generateTitle generate a Text of checkRun for the given state
+func generateCheckRunText(k8sClient client.Client, ctx context.Context, integrationTestStatusDetail intgteststat.IntegrationTestStatusDetail, namespace string) (string, error) {
+ if integrationTestStatusDetail.Status == intgteststat.IntegrationTestStatusTestPassed || integrationTestStatusDetail.Status == intgteststat.IntegrationTestStatusTestFail {
+ pipelineRunName := integrationTestStatusDetail.TestPipelineRunName
+ pipelineRun := &tektonv1beta1.PipelineRun{}
+ err := k8sClient.Get(ctx, types.NamespacedName{
+ Namespace: namespace,
+ Name: pipelineRunName,
+ }, pipelineRun)
+ if err != nil {
+ return "", fmt.Errorf("error while getting the pipelineRun %s: %w", pipelineRunName, err)
+ }
+
+ taskRuns, err := helpers.GetAllChildTaskRunsForPipelineRun(k8sClient, ctx, pipelineRun)
+ if err != nil {
+ return "", fmt.Errorf("error while getting all child taskRuns from pipelineRun %s: %w", pipelineRunName, err)
+ }
+ text, err := FormatSummary(taskRuns)
+ if err != nil {
+ return "", err
+ }
+ return text, nil
+ } else {
+ text := integrationTestStatusDetail.Details
+ return text, nil
+ }
+}
+
// generateCheckRunConclusion generate a conclusion as the conclusion of CheckRun
-// can be Can be one of: action_required, cancelled, failure, neutral, success, skipped, stale, timed_out
+// Can be one of: action_required, cancelled, failure, neutral, success, skipped, stale, timed_out
// https://docs.github.com/en/rest/checks/runs?apiVersion=2022-11-28#create-a-check-run
func generateCheckRunConclusion(state intgteststat.IntegrationTestStatus) (string, error) {
var conclusion string
@@ -317,7 +279,8 @@ func generateCommitState(state intgteststat.IntegrationTestStatus) (string, erro
// createCheckRunAdapterForSnapshot create a CheckRunAdapter for given snapshot, integrationTestStatusDetail, owner, repo and sha to create a checkRun
// https://docs.github.com/en/rest/checks/runs?apiVersion=2022-11-28#create-a-check-run
-func (r *GitHubReporter) createCheckRunAdapterForSnapshot(snapshot *applicationapiv1alpha1.Snapshot, integrationTestStatusDetail intgteststat.IntegrationTestStatusDetail, owner, repo, sha string) (*github.CheckRunAdapter, error) {
+func (r *GitHubReporter) createCheckRunAdapterForSnapshot(ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot, integrationTestStatusDetail intgteststat.IntegrationTestStatusDetail, owner, repo, sha string) (*github.CheckRunAdapter, error) {
+ var text string
snapshotName := snapshot.Name
scenarioName := integrationTestStatusDetail.ScenarioName
@@ -326,11 +289,21 @@ func (r *GitHubReporter) createCheckRunAdapterForSnapshot(snapshot *applicationa
return nil, fmt.Errorf("unknown status %s for integrationTestScenario %s and snapshot %s/%s", integrationTestStatusDetail.Status, scenarioName, snapshot.Namespace, snapshot.Name)
}
+ title, err := generateCheckRunTitle(integrationTestStatusDetail.Status)
+ if err != nil {
+ return nil, fmt.Errorf("unknown status %s for integrationTestScenario %s and snapshot %s/%s", integrationTestStatusDetail.Status, scenarioName, snapshot.Namespace, snapshot.Name)
+ }
+
summary, err := generateSummary(integrationTestStatusDetail.Status, snapshotName, scenarioName)
if err != nil {
return nil, fmt.Errorf("unknown status %s for integrationTestScenario %s and snapshot %s/%s", integrationTestStatusDetail.Status, scenarioName, snapshot.Namespace, snapshot.Name)
}
+ text, err = generateCheckRunText(r.k8sClient, ctx, integrationTestStatusDetail, snapshot.Namespace)
+ if err != nil {
+ return nil, fmt.Errorf("experienced error when generating text for checkRun: %w", err)
+ }
+
cra := &github.CheckRunAdapter{
Owner: owner,
Repository: repo,
@@ -338,10 +311,9 @@ func (r *GitHubReporter) createCheckRunAdapterForSnapshot(snapshot *applicationa
SHA: sha,
ExternalID: scenarioName,
Conclusion: conclusion,
- Title: conclusion,
- // This summary will be reworked once PLNSRVCE-1295 is implemented in the future
- Summary: summary,
- Text: integrationTestStatusDetail.Details,
+ Title: title,
+ Summary: summary,
+ Text: text,
}
if start := integrationTestStatusDetail.StartTime; start != nil {
@@ -355,69 +327,6 @@ func (r *GitHubReporter) createCheckRunAdapterForSnapshot(snapshot *applicationa
return cra, nil
}
-func (r *GitHubReporter) createCommitStatus(k8sClient client.Client, ctx context.Context, pipelineRun *tektonv1beta1.PipelineRun) error {
- var (
- state string
- description string
- )
-
- labels := pipelineRun.GetLabels()
-
- scenario, found := labels[gitops.SnapshotTestScenarioLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.SnapshotTestScenarioLabel)
- }
-
- component, found := labels[gitops.SnapshotComponentLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.SnapshotComponentLabel)
- }
-
- owner, found := labels[gitops.PipelineAsCodeURLOrgLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLOrgLabel)
- }
-
- repo, found := labels[gitops.PipelineAsCodeURLRepositoryLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLRepositoryLabel)
- }
-
- SHA, found := labels[gitops.PipelineAsCodeSHALabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeSHALabel)
- }
-
- statusContext := NamePrefix + " / " + component + " / " + scenario
-
- succeeded := pipelineRun.Status.GetCondition(apis.ConditionSucceeded)
-
- if succeeded.IsUnknown() {
- state = "pending"
- description = scenario + " has started"
- } else {
- outcome, err := helpers.GetIntegrationPipelineRunOutcome(k8sClient, ctx, pipelineRun)
- if err != nil {
- return err
- }
-
- if outcome.HasPipelineRunPassedTesting() {
- state = "success"
- description = scenario + " has succeeded"
- } else {
- state = "failure"
- description = scenario + " has failed"
- }
- }
-
- _, err := r.client.CreateCommitStatus(ctx, owner, repo, SHA, state, description, statusContext)
- if err != nil {
- return err
- }
-
- return nil
-}
-
// createCommitStatusAdapterForSnapshot create a commitStatusAdapter used to create commitStatus on GitHub
// https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#create-a-commit-status
func (r *GitHubReporter) createCommitStatusAdapterForSnapshot(snapshot *applicationapiv1alpha1.Snapshot, integrationTestStatusDetail intgteststat.IntegrationTestStatusDetail, owner, repo, sha string) (*github.CommitStatusAdapter, error) {
@@ -445,32 +354,11 @@ func (r *GitHubReporter) createCommitStatusAdapterForSnapshot(snapshot *applicat
}, nil
}
-func (r *GitHubReporter) createComment(k8sClient client.Client, ctx context.Context, pipelineRun *tektonv1beta1.PipelineRun) error {
- labels := pipelineRun.GetLabels()
-
- succeeded := pipelineRun.Status.GetCondition(apis.ConditionSucceeded)
- if succeeded.IsUnknown() {
- return nil
- }
-
- scenario, found := labels[gitops.SnapshotTestScenarioLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.SnapshotTestScenarioLabel)
- }
-
- owner, found := labels[gitops.PipelineAsCodeURLOrgLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLOrgLabel)
- }
-
- repo, found := labels[gitops.PipelineAsCodeURLRepositoryLabel]
- if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLRepositoryLabel)
- }
-
- issueNumberStr, found := pipelineRun.GetAnnotations()[gitops.PipelineAsCodePullRequestAnnotation]
+// UpdateStatusInComment will create/update a comment in PR which creates snapshot
+func (r *GitHubReporter) UpdateStatusInComment(k8sClient client.Client, ctx context.Context, snapshot *applicationapiv1alpha1.Snapshot, integrationTestStatusDetail intgteststat.IntegrationTestStatusDetail, repo, owner string) error {
+ issueNumberStr, found := snapshot.GetAnnotations()[gitops.PipelineAsCodePullRequestAnnotation]
if !found {
- return fmt.Errorf("PipelineRun label not found %q", gitops.PipelineAsCodeURLRepositoryLabel)
+ return fmt.Errorf("pull-request annotation not found %q", gitops.PipelineAsCodePullRequestAnnotation)
}
issueNumber, err := strconv.Atoi(issueNumberStr)
@@ -478,100 +366,61 @@ func (r *GitHubReporter) createComment(k8sClient client.Client, ctx context.Cont
return err
}
- outcome, err := helpers.GetIntegrationPipelineRunOutcome(k8sClient, ctx, pipelineRun)
- if err != nil {
- return err
- }
-
- var title string
- if outcome.HasPipelineRunPassedTesting() {
- title = scenario + " has succeeded"
- } else {
- title = scenario + " has failed"
- }
-
- taskRuns, err := helpers.GetAllChildTaskRunsForPipelineRun(r.k8sClient, ctx, pipelineRun)
- if err != nil {
- return fmt.Errorf("error while getting all child taskRuns from pipelineRun %s: %w", pipelineRun.Name, err)
- }
- comment, err := FormatComment(title, taskRuns)
- if err != nil {
- return err
- }
-
- _, err = r.client.CreateComment(ctx, owner, repo, issueNumber, comment)
+ state := integrationTestStatusDetail.Status
+ title, err := generateSummary(state, snapshot.Name, integrationTestStatusDetail.ScenarioName)
if err != nil {
- return err
+ return fmt.Errorf("unknown status %s for integrationTestScenario %s and snapshot %s/%s", integrationTestStatusDetail.Status, integrationTestStatusDetail.ScenarioName, snapshot.Namespace, snapshot.Name)
}
- return nil
-}
-
-// ReportStatus creates/updates CheckRuns when using GitHub App integration.
-// When using GitHub webhook integration a commit status and, in some cases, a comment is created.
-func (r *GitHubReporter) ReportStatus(k8sClient client.Client, ctx context.Context, pipelineRun *tektonv1beta1.PipelineRun) error {
- if !metadata.HasLabelWithValue(pipelineRun, gitops.PipelineAsCodeEventTypeLabel, gitops.PipelineAsCodePullRequestType) {
- return nil
- }
-
- // Existence of the Pipelines as Code installation ID annotation signals configuration using GitHub App integration.
- // If it doesn't exist, GitHub webhook integration is configured.
- if metadata.HasAnnotation(pipelineRun, gitops.PipelineAsCodeInstallationIDAnnotation) {
- creds, err := r.getAppCredentials(ctx, pipelineRun)
+ var comment string
+ if state == intgteststat.IntegrationTestStatusTestPassed || state == intgteststat.IntegrationTestStatusTestFail {
+ pipelineRunName := integrationTestStatusDetail.TestPipelineRunName
+ pipelineRun := &tektonv1beta1.PipelineRun{}
+ err := r.k8sClient.Get(ctx, types.NamespacedName{
+ Namespace: snapshot.Namespace,
+ Name: pipelineRunName,
+ }, pipelineRun)
if err != nil {
- return err
+ return fmt.Errorf("error while getting the pipelineRun %s: %w", pipelineRunName, err)
}
- token, err := r.client.CreateAppInstallationToken(ctx, creds.AppID, creds.InstallationID, creds.PrivateKey)
+ taskRuns, err := helpers.GetAllChildTaskRunsForPipelineRun(r.k8sClient, ctx, pipelineRun)
if err != nil {
- return err
+ return fmt.Errorf("error while getting all child taskRuns from pipelineRun %s: %w", pipelineRunName, err)
}
-
- r.client.SetOAuthToken(ctx, token)
-
- checkRun, err := r.createCheckRunAdapter(k8sClient, ctx, pipelineRun)
+ comment, err = FormatCommentForFinishedPipelineRun(title, taskRuns)
if err != nil {
- return err
- }
-
- checkRunID, err := r.client.GetCheckRunID(ctx, checkRun.Owner, checkRun.Repository, checkRun.SHA, checkRun.ExternalID, creds.AppID)
- if err != nil {
- return err
- }
-
- if checkRunID == nil {
- _, err = r.client.CreateCheckRun(ctx, checkRun)
- } else {
- err = r.client.UpdateCheckRun(ctx, *checkRunID, checkRun)
- }
-
- if err != nil {
- return err
+ return fmt.Errorf("error while formating all child taskRuns from pipelineRun %s: %w", pipelineRun.Name, err)
}
} else {
- token, err := r.getToken(ctx, pipelineRun, pipelineRun.Namespace)
+ comment, err = FormatCommentForDetail(title, integrationTestStatusDetail.Details)
if err != nil {
return err
}
+ }
- r.client.SetOAuthToken(ctx, token)
-
- err = r.createCommitStatus(k8sClient, ctx, pipelineRun)
+ allComments, err := r.client.GetAllCommentsForPR(ctx, owner, repo, issueNumber)
+ if err != nil {
+ return fmt.Errorf("error while getting all comments for pull-request %s: %w", issueNumberStr, err)
+ }
+ existingCommentId := r.client.GetExistingCommentID(allComments, snapshot.Name, integrationTestStatusDetail.ScenarioName)
+ if existingCommentId == nil {
+ _, err = r.client.CreateComment(ctx, owner, repo, issueNumber, comment)
if err != nil {
- return err
+ return fmt.Errorf("error while creating comment for pull-request %s: %w", issueNumberStr, err)
}
-
- err = r.createComment(k8sClient, ctx, pipelineRun)
+ } else {
+ _, err = r.client.EditComment(ctx, owner, repo, *existingCommentId, comment)
if err != nil {
- return err
+ return fmt.Errorf("error while updating comment for pull-request %s: %w", issueNumberStr, err)
}
}
return nil
}
-// ReportStatusForSnapshot creates CheckRun when using GitHub App integration,
-// creates a a commit status when using GitHub webhook integration
+// ReportStatusForSnapshot creates CheckRun when using GitHub App integration.
+// When using GitHub webhook integration it creates a commit status and a comment.
func (r *GitHubReporter) ReportStatusForSnapshot(k8sClient client.Client, ctx context.Context, logger *helpers.IntegrationLogger, snapshot *applicationapiv1alpha1.Snapshot) error {
statuses, err := gitops.NewSnapshotIntegrationTestStatusesFromSnapshot(snapshot)
if err != nil {
@@ -625,7 +474,7 @@ func (r *GitHubReporter) ReportStatusForSnapshot(k8sClient client.Client, ctx co
for _, integrationTestStatusDetail := range integrationTestStatusDetails {
integrationTestStatusDetail := *integrationTestStatusDetail // G601
- checkRun, err := r.createCheckRunAdapterForSnapshot(snapshot, integrationTestStatusDetail, owner, repo, sha)
+ checkRun, err := r.createCheckRunAdapterForSnapshot(ctx, snapshot, integrationTestStatusDetail, owner, repo, sha)
if err != nil {
logger.Error(err, "failed to create checkRunAdapter for snapshot",
"snapshot.NameSpace", snapshot.Namespace, "snapshot.Name", snapshot.Name)
@@ -698,6 +547,13 @@ func (r *GitHubReporter) ReportStatusForSnapshot(k8sClient client.Client, ctx co
if err != nil {
return err
}
+ // Create a comment when integration test is neither pending nor inprogress since comment for pending/inprogress is less meaningful and there is commitStatus for all statuses
+ if integrationTestStatusDetail.Status != intgteststat.IntegrationTestStatusPending && integrationTestStatusDetail.Status != intgteststat.IntegrationTestStatusInProgress {
+ err = r.UpdateStatusInComment(k8sClient, ctx, snapshot, integrationTestStatusDetail, repo, owner)
+ if err != nil {
+ return err
+ }
+ }
} else {
logger.Info("found existing commitStatus for scenario test status of snapshot, no need to create new commit status",
"snapshot.NameSpace", snapshot.Namespace, "snapshot.Name", snapshot.Name, "scenarioName", integrationTestStatusDetail.ScenarioName)
diff --git a/status/reporters_test.go b/status/reporters_test.go
index c8056c85f..ed6b04a89 100644
--- a/status/reporters_test.go
+++ b/status/reporters_test.go
@@ -17,9 +17,8 @@ limitations under the License.
package status_test
import (
+ "bytes"
"context"
- "fmt"
- "strings"
"time"
"k8s.io/apimachinery/pkg/api/meta"
@@ -36,10 +35,10 @@ import (
"github.com/redhat-appstudio/integration-service/helpers"
"github.com/redhat-appstudio/integration-service/status"
tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
+ "github.com/tonglil/buflogr"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- "knative.dev/pkg/apis"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -75,6 +74,12 @@ type CreateCommentResult struct {
issueNumber int
}
+type EditCommentResult struct {
+ ID int64
+ Error error
+ body string
+}
+
type CreateCommitStatusResult struct {
ID int64
Error error
@@ -91,6 +96,7 @@ type MockGitHubClient struct {
GetCheckRunResult
CreateCommentResult
CreateCommitStatusResult
+ EditCommentResult
}
func (c *MockGitHubClient) CreateAppInstallationToken(ctx context.Context, appID int64, installationID int64, privateKey []byte) (string, error) {
@@ -122,6 +128,13 @@ func (c *MockGitHubClient) GetExistingCheckRun(checkRuns []*ghapi.CheckRun, cra
}
func (c *MockGitHubClient) CommitStatusExists(res []*ghapi.RepoStatus, commitStatus *github.CommitStatusAdapter) (bool, error) {
+ for _, cs := range res {
+ if *cs.State == commitStatus.State && *cs.Description == commitStatus.Description && *cs.Context == commitStatus.Context {
+ return true, nil
+ } else {
+ return false, nil
+ }
+ }
return false, nil
}
@@ -131,7 +144,25 @@ func (c *MockGitHubClient) CreateComment(ctx context.Context, owner string, repo
return c.CreateCommentResult.ID, c.CreateCommentResult.Error
}
+func (c *MockGitHubClient) EditComment(ctx context.Context, owner string, repo string, commentID int64, body string) (int64, error) {
+ c.EditCommentResult.body = body
+ c.EditCommentResult.ID = commentID
+ return c.EditCommentResult.ID, c.EditCommentResult.Error
+}
+
+func (c *MockGitHubClient) GetAllCommentsForPR(ctx context.Context, owner string, repo string, pr int) ([]*ghapi.IssueComment, error) {
+ var id int64 = 20
+ comments := []*ghapi.IssueComment{{ID: &id}}
+ return comments, nil
+}
+
+func (c *MockGitHubClient) GetExistingCommentID(comments []*ghapi.IssueComment, snapshotName, scenarioName string) *int64 {
+ return nil
+}
+
func (c *MockGitHubClient) CreateCommitStatus(ctx context.Context, owner string, repo string, SHA string, state string, description string, statusContext string) (int64, error) {
+ var id int64 = 60
+ c.CreateCommitStatusResult.ID = id
c.CreateCommitStatusResult.state = state
c.CreateCommitStatusResult.description = description
c.CreateCommitStatusResult.statusContext = statusContext
@@ -150,8 +181,10 @@ func (c *MockGitHubClient) GetAllCheckRunsForRef(
func (c *MockGitHubClient) GetAllCommitStatusesForRef(
ctx context.Context, owner, repo, sha string) ([]*ghapi.RepoStatus, error) {
var id int64 = 60
- var state = "success"
- repoStatus := &ghapi.RepoStatus{ID: &id, State: &state}
+ var state = "pending"
+ var description = "Integration test for snapshot snapshot-sample and scenario scenario2 is pending"
+ var statusContext = "Red Hat Trusted App Test / snapshot-sample / scenario2"
+ repoStatus := &ghapi.RepoStatus{ID: &id, State: &state, Context: &statusContext, Description: &description}
return []*ghapi.RepoStatus{repoStatus}, nil
}
@@ -227,25 +260,6 @@ func (c *MockK8sClient) RESTMapper() meta.RESTMapper {
panic("implement me")
}
-func setPipelineRunOutcome(pipelineRun *tektonv1beta1.PipelineRun, taskRun *tektonv1beta1.TaskRun) {
- pipelineRun.Status = tektonv1beta1.PipelineRunStatus{
- PipelineRunStatusFields: tektonv1beta1.PipelineRunStatusFields{
- CompletionTime: &metav1.Time{Time: time.Now()},
- ChildReferences: []tektonv1beta1.ChildStatusReference{
- {
- Name: taskRun.Name,
- PipelineTaskName: "pipeline1-task1",
- },
- },
- },
- }
- pipelineRun.Status.SetCondition(&apis.Condition{
- Type: apis.ConditionSucceeded,
- Message: "sample msg",
- Status: "True",
- })
-}
-
var _ = Describe("GitHubReporter", func() {
var reporter *status.GitHubReporter
@@ -432,7 +446,6 @@ var _ = Describe("GitHubReporter", func() {
var secretData map[string][]byte
BeforeEach(func() {
- pipelineRun.Annotations["pac.test.appstudio.openshift.io/installation-id"] = "123"
hasSnapshot.Annotations["pac.test.appstudio.openshift.io/installation-id"] = "123"
secretData = map[string][]byte{
@@ -454,6 +467,11 @@ var _ = Describe("GitHubReporter", func() {
taskRun.Status = skippedTaskRun.Status
}
}
+ if plr, ok := obj.(*tektonv1beta1.PipelineRun); ok {
+ if key.Name == pipelineRun.Name {
+ plr.Status = pipelineRun.Status
+ }
+ }
},
listInterceptor: func(list client.ObjectList) {},
}
@@ -463,86 +481,41 @@ var _ = Describe("GitHubReporter", func() {
})
It("doesn't report status for non-pull request events", func() {
- delete(pipelineRun.Labels, "pac.test.appstudio.openshift.io/event-type")
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
delete(hasSnapshot.Labels, "pac.test.appstudio.openshift.io/event-type")
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
})
It("doesn't report status when the credentials are invalid/missing", func() {
// Invalid installation ID value
- pipelineRun.Annotations["pac.test.appstudio.openshift.io/installation-id"] = "bad-installation-id"
- err := reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)
- Expect(err).ToNot(BeNil())
- pipelineRun.Annotations["pac.test.appstudio.openshift.io/installation-id"] = "123"
-
hasSnapshot.Annotations["pac.test.appstudio.openshift.io/installation-id"] = "bad-installation-id"
- err = reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)
+ err := reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)
Expect(err).ToNot(BeNil())
hasSnapshot.Annotations["pac.test.appstudio.openshift.io/installation-id"] = "123"
// Invalid app ID value
secretData["github-application-id"] = []byte("bad-app-id")
- err = reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)
- Expect(err).ToNot(BeNil())
err = reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)
Expect(err).ToNot(BeNil())
secretData["github-application-id"] = []byte("456")
// Missing app ID value
delete(secretData, "github-application-id")
- err = reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)
- Expect(err).ToNot(BeNil())
err = reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)
Expect(err).ToNot(BeNil())
secretData["github-application-id"] = []byte("456")
// Missing private key
delete(secretData, "github-private-key")
- err = reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)
- Expect(err).ToNot(BeNil())
err = reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)
Expect(err).ToNot(BeNil())
})
- It("reports status via CheckRuns", func() {
- // Create an in progress CheckRun
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.CreateCheckRunResult.cra.Title).To(Equal("example-pass has started"))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.Conclusion).To(Equal(""))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.ExternalID).To(Equal(pipelineRun.Name))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.Owner).To(Equal("devfile-sample"))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.Repository).To(Equal("devfile-sample-go-basic"))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.SHA).To(Equal("12a4a35ccd08194595179815e4646c3a6c08bb77"))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.Name).To(Equal("Red Hat Trusted App Test / devfile-sample-go-basic / example-pass"))
- Expect(mockGitHubClient.CreateCheckRunResult.cra.StartTime.IsZero()).To(BeFalse())
- Expect(mockGitHubClient.CreateCheckRunResult.cra.CompletionTime.IsZero()).To(BeTrue())
- Expect(mockGitHubClient.CreateCheckRunResult.cra.Text).To(Equal(""))
-
- // Update existing CheckRun w/success
- setPipelineRunOutcome(pipelineRun, successfulTaskRun)
- var id int64 = 1
- mockGitHubClient.GetCheckRunIDResult.ID = &id
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.UpdateCheckRunResult.cra.Title).To(Equal("example-pass has succeeded"))
- Expect(mockGitHubClient.UpdateCheckRunResult.cra.Conclusion).To(Equal("success"))
- Expect(mockGitHubClient.UpdateCheckRunResult.cra.CompletionTime.IsZero()).To(BeFalse())
- Expect(mockGitHubClient.UpdateCheckRunResult.cra.Text).To(Equal("sample msg"))
-
- // Update existing CheckRun w/failure
- setPipelineRunOutcome(pipelineRun, failedTaskRun)
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.UpdateCheckRunResult.cra.Title).To(Equal("example-pass has failed"))
- Expect(mockGitHubClient.UpdateCheckRunResult.cra.Conclusion).To(Equal("failure"))
- })
-
It("reports snapshot tests status via CheckRuns", func() {
// Create an pending CheckRun
hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"Pending\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"pending\"}]"
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.CreateCheckRunResult.cra.Summary).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 is pending"))
Expect(mockGitHubClient.CreateCheckRunResult.cra.Conclusion).To(Equal(""))
- fmt.Fprintf(GinkgoWriter, "-------Time: %v\n", mockGitHubClient.CreateCheckRunResult.cra.StartTime)
// Update existing CheckRun w/inprogress
hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"InProgress\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"Failed to find deploymentTargetClass with right provisioner for copy of existingEnvironment\"}]"
@@ -576,17 +549,18 @@ var _ = Describe("GitHubReporter", func() {
Expect(mockGitHubClient.UpdateCheckRunResult.cra.Conclusion).To(Equal(gitops.IntegrationTestStatusFailureGithub))
Expect(mockGitHubClient.UpdateCheckRunResult.cra.CompletionTime.IsZero()).To(BeFalse())
- hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestFail\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestFail\",\"testPipelineRunName\":\"test-pipelinerun\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.UpdateCheckRunResult.cra.Summary).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 has failed"))
Expect(mockGitHubClient.UpdateCheckRunResult.cra.Conclusion).To(Equal(gitops.IntegrationTestStatusFailureGithub))
Expect(mockGitHubClient.UpdateCheckRunResult.cra.CompletionTime.IsZero()).To(BeFalse())
// Update existing CheckRun w/success
- hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestPassed\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestPassed\",\"testPipelineRunName\":\"test-pipelinerun\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.UpdateCheckRunResult.cra.Summary).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 has passed"))
Expect(mockGitHubClient.UpdateCheckRunResult.cra.Conclusion).To(Equal(gitops.IntegrationTestStatusSuccessGithub))
+ Expect(mockGitHubClient.UpdateCheckRunResult.cra.Title).To(Equal("Succeeded"))
})
})
@@ -594,9 +568,10 @@ var _ = Describe("GitHubReporter", func() {
var secretData map[string][]byte
var repo pacv1alpha1.Repository
+ var buf bytes.Buffer
+ log := helpers.IntegrationLogger{Logger: buflogr.NewWithBuffer(&buf)}
BeforeEach(func() {
- pipelineRun.Annotations["pac.test.appstudio.openshift.io/pull-request"] = "999"
hasSnapshot.Annotations["pac.test.appstudio.openshift.io/pull-request"] = "999"
repo = pacv1alpha1.Repository{
@@ -625,6 +600,11 @@ var _ = Describe("GitHubReporter", func() {
taskRun.Status = skippedTaskRun.Status
}
}
+ if plr, ok := obj.(*tektonv1beta1.PipelineRun); ok {
+ if key.Name == pipelineRun.Name {
+ plr.Status = pipelineRun.Status
+ }
+ }
},
listInterceptor: func(list client.ObjectList) {
if repoList, ok := list.(*pacv1alpha1.RepositoryList); ok {
@@ -641,88 +621,58 @@ var _ = Describe("GitHubReporter", func() {
reporter = status.NewGitHubReporter(logr.Discard(), mockK8sClient, status.WithGitHubClient(mockGitHubClient))
})
- It("doesn't report status for non-pull request events", func() {
- delete(pipelineRun.Labels, "pac.test.appstudio.openshift.io/event-type")
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- })
-
- It("creates a comment for a succeeded PipelineRun", func() {
- pipelineRun.Status.SetCondition(&apis.Condition{
- Type: apis.ConditionSucceeded,
- Status: "True",
- })
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.CreateCommentResult.body).To(ContainSubstring("# example-pass has succeeded"))
- Expect(mockGitHubClient.CreateCommentResult.issueNumber).To(Equal(999))
- })
-
- It("creates a comment for a failed PipelineRun", func() {
- setPipelineRunOutcome(pipelineRun, failedTaskRun)
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- called := strings.Contains(mockGitHubClient.CreateCommentResult.body, "# example-pass has failed")
- Expect(called).To(BeTrue())
- Expect(mockGitHubClient.CreateCommentResult.issueNumber).To(Equal(999))
- })
-
- It("doesn't create a comment for non-completed PipelineRuns", func() {
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.CreateCommentResult.body).To(Equal(""))
- Expect(mockGitHubClient.CreateCommentResult.issueNumber).To(Equal(0))
- })
-
- It("creates a commit status", func() {
- // In progress
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal("pending"))
- Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("example-pass has started"))
- Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / devfile-sample-go-basic / example-pass"))
-
- // Success
- pipelineRun.Status.SetCondition(&apis.Condition{
- Type: apis.ConditionSucceeded,
- Status: "True",
- })
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal("success"))
- Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("example-pass has succeeded"))
- Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / devfile-sample-go-basic / example-pass"))
-
- // Failure
- setPipelineRunOutcome(pipelineRun, failedTaskRun)
- Expect(reporter.ReportStatus(mockK8sClient, context.TODO(), pipelineRun)).To(BeNil())
- Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal("failure"))
- Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("example-pass has failed"))
- Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / devfile-sample-go-basic / example-pass"))
- })
-
It("creates a commit status for snapshot", func() {
- // Error
+ // EnvironmentProvisionError
hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"EnvironmentProvisionError\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
-
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal(gitops.IntegrationTestStatusErrorGithub))
Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 experienced an error when provisioning environment"))
Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / snapshot-sample / scenario1"))
+ Expect(mockGitHubClient.CreateCommentResult.body).Should(ContainSubstring("experienced an error when provisioning environment"))
+ // DeploymentError
hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"DeploymentError\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal(gitops.IntegrationTestStatusErrorGithub))
Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 experienced an error when deploying snapshotEnvironmentBinding"))
Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / snapshot-sample / scenario1"))
+ Expect(mockGitHubClient.CreateCommentResult.body).Should(ContainSubstring("experienced an error when deploying snapshotEnvironmentBinding"))
// Success
- hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestPassed\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"passed\"}]"
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestPassed\",\"testPipelineRunName\":\"test-pipelinerun\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"passed\"}]"
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal(gitops.IntegrationTestStatusSuccessGithub))
Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 has passed"))
Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / snapshot-sample / scenario1"))
+ Expect(mockGitHubClient.CreateCommentResult.body).Should(ContainSubstring("has passed"))
- // Failure
- hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestFail\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"passed\"}]"
+ // TestFail
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"TestFail\",\"testPipelineRunName\":\"test-pipelinerun\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"completionTime\":\"2023-07-26T17:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"failed\"}]"
Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal(gitops.IntegrationTestStatusFailureGithub))
Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 has failed"))
Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / snapshot-sample / scenario1"))
+ Expect(mockGitHubClient.CreateCommentResult.body).Should(ContainSubstring("has failed"))
+
+ // InProgress
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"InProgress\",\"startTime\":\"2023-07-26T16:57:49+02:00\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"In progress\"}]"
+ Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &logger, hasSnapshot)).To(BeNil())
+ Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal(gitops.IntegrationTestStatusPendingGithub))
+ Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 is in progress"))
+ Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / snapshot-sample / scenario1"))
+
+ // Pending
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario1\",\"status\":\"Pending\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"pending\"}]"
+ Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &log, hasSnapshot)).To(BeNil())
+ Expect(mockGitHubClient.CreateCommitStatusResult.state).To(Equal(gitops.IntegrationTestStatusPendingGithub))
+ Expect(mockGitHubClient.CreateCommitStatusResult.description).To(Equal("Integration test for snapshot snapshot-sample and scenario scenario1 is pending"))
+ Expect(mockGitHubClient.CreateCommitStatusResult.statusContext).To(Equal("Red Hat Trusted App Test / snapshot-sample / scenario1"))
+
+ // One commitStatus exists already
+ hasSnapshot.Annotations["test.appstudio.openshift.io/status"] = "[{\"scenario\":\"scenario2\",\"status\":\"Pending\",\"lastUpdateTime\":\"2023-08-26T17:57:49+02:00\",\"details\":\"pending\"}]"
+ Expect(reporter.ReportStatusForSnapshot(mockK8sClient, context.TODO(), &log, hasSnapshot)).To(BeNil())
+ expectedLogEntry := "found existing commitStatus for scenario test status of snapshot, no need to create new commit status"
+ Expect(buf.String()).Should(ContainSubstring(expectedLogEntry))
})
})
})
diff --git a/status/status.go b/status/status.go
index 5d62757bd..9b112a154 100644
--- a/status/status.go
+++ b/status/status.go
@@ -24,7 +24,6 @@ import (
"github.com/redhat-appstudio/integration-service/gitops"
"github.com/redhat-appstudio/integration-service/helpers"
"github.com/redhat-appstudio/operator-toolkit/metadata"
- tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -33,7 +32,6 @@ const NamePrefix = "Red Hat Trusted App Test"
// Reporter is a generic interface all status implementations must follow.
type Reporter interface {
- ReportStatus(client.Client, context.Context, *tektonv1beta1.PipelineRun) error
ReportStatusForSnapshot(client.Client, context.Context, *helpers.IntegrationLogger, *applicationapiv1alpha1.Snapshot) error
}
diff --git a/status/status_test.go b/status/status_test.go
index 0e620c320..5a4cea071 100644
--- a/status/status_test.go
+++ b/status/status_test.go
@@ -33,10 +33,6 @@ import (
type MockReporter struct{}
-func (r *MockReporter) ReportStatus(client.Client, context.Context, *tektonv1beta1.PipelineRun) error {
- return nil
-}
-
func (r *MockReporter) ReportStatusForSnapshot(client.Client, context.Context, *helpers.IntegrationLogger, *applicationapiv1alpha1.Snapshot) error {
return nil
}