Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions pkg/services/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package services
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"regexp"
Expand Down Expand Up @@ -41,6 +42,7 @@ type GitHubNotification struct {
RepoURLPath string `json:"repoURLPath,omitempty"`
RevisionPath string `json:"revisionPath,omitempty"`
CheckRun *GitHubCheckRun `json:"checkRun,omitempty"`
RepositoryDispatch *GitHubRepositoryDispatch `json:"repositoryDispatch,omitempty"`
}

type GitHubStatus struct {
Expand Down Expand Up @@ -82,6 +84,11 @@ type GitHubPullRequestComment struct {
CommentTag string `json:"commentTag,omitempty"`
}

type GitHubRepositoryDispatch struct {
EventType string `json:"event_type,omitempty"`
ClientPayload string `json:"client_payload,omitempty"`
}

const (
repoURLtemplate = "{{.app.spec.source.repoURL}}"
revisionTemplate = "{{.app.status.operationState.syncResult.revision}}"
Expand Down Expand Up @@ -204,6 +211,18 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
}
}

var repoDispatchEventType, repoDispatchClientPayload *texttemplate.Template
if g.RepositoryDispatch != nil {
repoDispatchEventType, err = texttemplate.New(name).Funcs(f).Parse(g.RepositoryDispatch.EventType)
if err != nil {
return nil, err
}
repoDispatchClientPayload, err = texttemplate.New(name).Funcs(f).Parse(g.RepositoryDispatch.ClientPayload)
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 @@ -375,6 +394,20 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
notification.GitHub.CheckRun.Output.Text = textData.String()
}

if g.RepositoryDispatch != nil {
notification.GitHub.RepositoryDispatch = &GitHubRepositoryDispatch{}
var eventTypeData bytes.Buffer
if err := repoDispatchEventType.Execute(&eventTypeData, vars); err != nil {
return err
}
notification.GitHub.RepositoryDispatch.EventType = eventTypeData.String()
var clientPayloadData bytes.Buffer
if err := repoDispatchClientPayload.Execute(&clientPayloadData, vars); err != nil {
return err
}
notification.GitHub.RepositoryDispatch.ClientPayload = clientPayloadData.String()
}

return nil
}, nil
}
Expand Down Expand Up @@ -445,6 +478,7 @@ type repositoriesService interface {
ListDeployments(ctx context.Context, owner, repo string, opts *github.DeploymentsListOptions) ([]*github.Deployment, *github.Response, error)
CreateDeployment(ctx context.Context, owner, repo string, request *github.DeploymentRequest) (*github.Deployment, *github.Response, error)
CreateDeploymentStatus(ctx context.Context, owner, repo string, deploymentID int64, request *github.DeploymentStatusRequest) (*github.DeploymentStatus, *github.Response, error)
Dispatch(ctx context.Context, owner, repo string, opts github.DispatchRequestOptions) (*github.Repository, *github.Response, error)
}

type checksService interface {
Expand Down Expand Up @@ -698,6 +732,23 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
}
}

if notification.GitHub.RepositoryDispatch != nil {
payload := json.RawMessage(notification.GitHub.RepositoryDispatch.ClientPayload)
_, _, err := g.client.GetRepositories().Dispatch(
context.Background(),
u[0],
u[1],
github.DispatchRequestOptions{
EventType: notification.GitHub.RepositoryDispatch.EventType,
ClientPayload: &payload,
},
)

if err != nil {
return err
}
}

return nil
}

Expand Down
89 changes: 84 additions & 5 deletions pkg/services/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,52 @@ func TestGetTemplater_Github_PullRequestComment(t *testing.T) {
assert.Equal(t, "This is a comment", notification.GitHub.PullRequestComment.Content)
}

func TestGetTemplater_Github_RepositoryDispatch(t *testing.T) {
n := Notification{
GitHub: &GitHubNotification{
RepoURLPath: "{{.sync.spec.git.repo}}",
RevisionPath: "{{.sync.status.lastSyncedCommit}}",
RepositoryDispatch: &GitHubRepositoryDispatch{
EventType: "sync",
ClientPayload: `{ "sha": "{{.sync.status.lastSyncedCommit}}" }`,
},
},
}
templater, err := n.GetTemplater("", template.FuncMap{})

if !assert.NoError(t, err) {
return
}

var notification Notification
err = templater(&notification, map[string]interface{}{
"sync": map[string]interface{}{
"metadata": map[string]interface{}{
"name": "root-sync-test",
},
"spec": map[string]interface{}{
"git": map[string]interface{}{
"repo": "https://github.com/argoproj-labs/argocd-notifications.git",
},
},
"status": map[string]interface{}{
"lastSyncedCommit": "0123456789",
},
},
})

if !assert.NoError(t, err) {
return
}

assert.Equal(t, "{{.sync.spec.git.repo}}", notification.GitHub.RepoURLPath)
assert.Equal(t, "{{.sync.status.lastSyncedCommit}}", notification.GitHub.RevisionPath)
assert.Equal(t, "https://github.com/argoproj-labs/argocd-notifications.git", notification.GitHub.repoURL)
assert.Equal(t, "0123456789", notification.GitHub.revision)
assert.Equal(t, "sync", notification.GitHub.RepositoryDispatch.EventType)
assert.Equal(t, `{ "sha": "0123456789" }`, notification.GitHub.RepositoryDispatch.ClientPayload)
}

func TestGetTemplater_Github_PullRequestCommentWithTag(t *testing.T) {
n := Notification{
GitHub: &GitHubNotification{
Expand Down Expand Up @@ -357,7 +403,9 @@ type mockPullRequestsService struct {
prs []*github.PullRequest
}

type mockRepositoriesService struct{}
type mockRepositoriesService struct {
dispatches []github.DispatchRequestOptions
}

func (m *mockRepositoriesService) CreateStatus(ctx context.Context, owner, repo, ref string, status *github.RepoStatus) (*github.RepoStatus, *github.Response, error) {
return status, nil, nil
Expand All @@ -375,6 +423,11 @@ func (m *mockRepositoriesService) CreateDeploymentStatus(ctx context.Context, ow
return &github.DeploymentStatus{}, nil, nil
}

func (m *mockRepositoriesService) Dispatch(ctx context.Context, owner, repo string, request github.DispatchRequestOptions) (*github.Repository, *github.Response, error) {
m.dispatches = append(m.dispatches, request)
return &github.Repository{}, nil, nil
}

type mockChecksService struct{}

func (m *mockChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opts github.CreateCheckRunOptions) (*github.CheckRun, *github.Response, error) {
Expand All @@ -394,20 +447,46 @@ func (m *mockGitHubClientImpl) GetPullRequests() pullRequestsService { return m.
func (m *mockGitHubClientImpl) GetRepositories() repositoriesService { return m.repos }
func (m *mockGitHubClientImpl) GetChecks() checksService { return m.checks }

func setupMockServices() (*mockIssuesService, *mockPullRequestsService, githubClient) {
func setupMockServices() (*mockIssuesService, *mockPullRequestsService, *mockRepositoriesService, githubClient) {
issues := &mockIssuesService{comments: []*github.IssueComment{}}
pulls := &mockPullRequestsService{prs: []*github.PullRequest{{Number: github.Ptr(1)}}}
repos := &mockRepositoriesService{}
client := &mockGitHubClientImpl{
issues: issues,
prs: pulls,
repos: &mockRepositoriesService{},
repos: repos,
checks: &mockChecksService{},
}
return issues, pulls, client
return issues, pulls, repos, client
}

func TestGitHubService_Send_RepositoryDispatch(t *testing.T) {
_, _, repos, client := setupMockServices()

service := &gitHubService{client: client}

err := service.Send(Notification{
GitHub: &GitHubNotification{
repoURL: "https://github.com/owner/repo",
revision: "abc123",
RepositoryDispatch: &GitHubRepositoryDispatch{
EventType: "sync",
ClientPayload: `{ "sha": "12345678" }`,
},
},
}, Destination{})

assert.NoError(t, err)
assert.Len(t, repos.dispatches, 1)
assert.Equal(t, repos.dispatches[0].EventType, "sync")

payload, err := repos.dispatches[0].ClientPayload.MarshalJSON()
assert.NoError(t, err)
assert.Equal(t, string(payload), `{ "sha": "12345678" }`)
}

func TestGitHubService_Send_PullRequestCommentWithTag(t *testing.T) {
issues, _, client := setupMockServices()
issues, _, _, client := setupMockServices()

service := &gitHubService{client: client}

Expand Down