Skip to content

Commit

Permalink
feat: Add GitHub Check Run Support (#344)
Browse files Browse the repository at this point in the history
* feat: Add Support for GitHub Check Runs

Signed-off-by: Yash Talele <[email protected]>

* Added test cases for github check run

Signed-off-by: Yash Talele <[email protected]>

* docs: add check run options for github

Signed-off-by: kswadi <[email protected]>

---------

Signed-off-by: Yash Talele <[email protected]>
Signed-off-by: kswadi <[email protected]>
Co-authored-by: kswadi <[email protected]>
Co-authored-by: Pasha Kostohrys <[email protected]>
  • Loading branch information
3 people authored Dec 18, 2024
1 parent 4fb0fb3 commit 8cb0e74
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 0 deletions.
13 changes: 13 additions & 0 deletions docs/services/github.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ template.app-deployed: |
content: |
Application {{.app.metadata.name}} is now running new version of deployments manifests.
See more here: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true
checkRun:
name: "continuous-delivery/{{.app.metadata.name}}"
details_url: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
status: completed
conclusion: success
started_at: "YYYY-MM-DDTHH:MM:SSZ"
completed_at: "YYYY-MM-DDTHH:MM:SSZ"
output:
title: "Deployment of {{.app.metadata.name}} on ArgoCD"
summary: "Application {{.app.metadata.name}} is now running new version of deployments manifests."
text: |
Application {{.app.metadata.name}} is now running new version of deployments manifests.
See more here: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true
```
**Notes**:
Expand Down
158 changes: 158 additions & 0 deletions pkg/services/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"regexp"
"strings"
texttemplate "text/template"
"time"
"unicode/utf8"

"github.com/bradleyfalzon/ghinstallation/v2"
Expand Down Expand Up @@ -39,6 +40,7 @@ type GitHubNotification struct {
PullRequestComment *GitHubPullRequestComment `json:"pullRequestComment,omitempty"`
RepoURLPath string `json:"repoURLPath,omitempty"`
RevisionPath string `json:"revisionPath,omitempty"`
CheckRun *GitHubCheckRun `json:"checkRun,omitempty"`
}

type GitHubStatus struct {
Expand All @@ -47,6 +49,23 @@ type GitHubStatus struct {
TargetURL string `json:"targetURL,omitempty"`
}

type GitHubCheckRun struct {
// head_sha - this will be the revision path
// external_id - this should have the details of argocd server
Name string `json:"name,omitempty"`
DetailsURL string `json:"details_url,omitempty"`
Status string `json:"status,omitempty"`
Conclusion string `json:"conclusion,omitempty"`
StartedAt string `json:"started_at,omitempty"`
CompletedAt string `json:"completed_at,omitempty"`
Output *GitHubCheckRunOutput `json:"output,omitempty"`
}
type GitHubCheckRunOutput struct {
Title string `json:"title,omitempty"`
Summary string `json:"summary,omitempty"`
Text string `json:"text,omitempty"`
}

type GitHubDeployment struct {
State string `json:"state,omitempty"`
Environment string `json:"environment,omitempty"`
Expand Down Expand Up @@ -139,6 +158,49 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
}
}

var checkRunName, detailsURL, status, conclusion, startedAt, completedAt *texttemplate.Template
if g.CheckRun != nil {
checkRunName, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.Name)
if err != nil {
return nil, err
}
detailsURL, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.DetailsURL)
if err != nil {
return nil, err
}
status, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.Status)
if err != nil {
return nil, err
}
conclusion, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.Conclusion)
if err != nil {
return nil, err
}
startedAt, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.StartedAt)
if err != nil {
return nil, err
}
completedAt, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.CompletedAt)
if err != nil {
return nil, err
}
}
var checkRunTitle, summary, text *texttemplate.Template
if g.CheckRun != nil && g.CheckRun.Output != nil {
checkRunTitle, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.Output.Title)
if err != nil {
return nil, err
}
summary, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.Output.Summary)
if err != nil {
return nil, err
}
text, err = texttemplate.New(name).Funcs(f).Parse(g.CheckRun.Output.Text)
if err != nil {
return nil, err
}
}

return func(notification *Notification, vars map[string]interface{}) error {
if notification.GitHub == nil {
notification.GitHub = &GitHubNotification{
Expand Down Expand Up @@ -246,6 +308,63 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
notification.GitHub.PullRequestComment.Content = contentData.String()
}

if g.CheckRun != nil {
if notification.GitHub.CheckRun == nil {
notification.GitHub.CheckRun = &GitHubCheckRun{}
}
var checkRunNameData bytes.Buffer
if err := checkRunName.Execute(&checkRunNameData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.Name = checkRunNameData.String()
var detailsURLData bytes.Buffer
if err := detailsURL.Execute(&detailsURLData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.DetailsURL = detailsURLData.String()

var statusData bytes.Buffer
if err := status.Execute(&statusData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.Status = statusData.String()
var conclusionData bytes.Buffer
if err := conclusion.Execute(&conclusionData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.Conclusion = conclusionData.String()
var startedAtData bytes.Buffer
if err := startedAt.Execute(&startedAtData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.StartedAt = startedAtData.String()
var completedAtData bytes.Buffer
if err := completedAt.Execute(&completedAtData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.CompletedAt = completedAtData.String()
}
if g.CheckRun != nil && g.CheckRun.Output != nil {
if notification.GitHub.CheckRun.Output == nil {
notification.GitHub.CheckRun.Output = &GitHubCheckRunOutput{}
}
var checkRunTitleData bytes.Buffer
if err := checkRunTitle.Execute(&checkRunTitleData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.Output.Title = checkRunTitleData.String()
var summaryData bytes.Buffer
if err := summary.Execute(&summaryData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.Output.Summary = summaryData.String()
var textData bytes.Buffer
if err := text.Execute(&textData, vars); err != nil {
return err
}
notification.GitHub.CheckRun.Output.Text = textData.String()
}

return nil
}, nil
}
Expand Down Expand Up @@ -438,5 +557,44 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
}
}

if notification.GitHub.CheckRun != nil {
startedTime, err := time.Parse("YYYY-MM-DDTHH:MM:SSZ", notification.GitHub.CheckRun.StartedAt)
if err != nil {
return err
}
completedTime, err := time.Parse("YYYY-MM-DDTHH:MM:SSZ", notification.GitHub.CheckRun.CompletedAt)
if err != nil {
return err
}
externalID := "argocd-notifications"
checkRunOutput := &github.CheckRunOutput{}
if notification.GitHub.CheckRun.Output != nil {
checkRunOutput = &github.CheckRunOutput{
Title: &notification.GitHub.CheckRun.Output.Title,
Text: &notification.GitHub.CheckRun.Output.Text,
Summary: &notification.GitHub.CheckRun.Output.Summary,
}
}

_, _, err = g.client.Checks.CreateCheckRun(
context.Background(),
u[0],
u[1],
github.CreateCheckRunOptions{
HeadSHA: notification.GitHub.revision,
ExternalID: &externalID,
Name: notification.GitHub.CheckRun.Name,
DetailsURL: &notification.GitHub.CheckRun.DetailsURL,
StartedAt: &github.Timestamp{Time: startedTime},
CompletedAt: &github.Timestamp{Time: completedTime},
Output: checkRunOutput,
},
)

if err != nil {
return err
}
}

return nil
}
53 changes: 53 additions & 0 deletions pkg/services/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package services
import (
"testing"
"text/template"
"time"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -261,3 +262,55 @@ func TestGetTemplater_Github_PullRequestComment(t *testing.T) {
assert.Equal(t, "0123456789", notification.GitHub.revision)
assert.Equal(t, "This is a comment", notification.GitHub.PullRequestComment.Content)
}

func TestGitHubCheckRunNotification(t *testing.T) {
checkRun := &GitHubCheckRun{
Name: "ArgoCD GitHub Check Run",
DetailsURL: "http://example.com/build/status",
Status: "completed",
Conclusion: "success",
StartedAt: time.Now().Format(time.RFC3339),
CompletedAt: time.Now().Add(5 * time.Minute).Format(time.RFC3339),
Output: &GitHubCheckRunOutput{
Title: "Test Check Run",
Summary: "All tests passed.",
Text: "All unit tests and integration tests passed successfully.",
},
}

githubNotification := &GitHubNotification{
CheckRun: checkRun,
}

vars := map[string]interface{}{
"app": map[string]interface{}{
"spec": map[string]interface{}{
"source": map[string]interface{}{
"repoURL": "https://github.com/argoproj/argo-cd.git",
},
},
"status": map[string]interface{}{
"operationState": map[string]interface{}{
"syncResult": map[string]interface{}{
"revision": "abc123",
},
},
},
},
}

templater, err := githubNotification.GetTemplater("checkRun", nil)
assert.NoError(t, err)

notification := &Notification{}

err = templater(notification, vars)
assert.NoError(t, err)

assert.NotNil(t, notification.GitHub)
assert.NotNil(t, notification.GitHub.CheckRun)
assert.Equal(t, "ArgoCD GitHub Check Run", notification.GitHub.CheckRun.Name)
assert.Equal(t, "completed", notification.GitHub.CheckRun.Status)
assert.Equal(t, "success", notification.GitHub.CheckRun.Conclusion)
assert.Equal(t, "All tests passed.", notification.GitHub.CheckRun.Output.Summary)
}

0 comments on commit 8cb0e74

Please sign in to comment.