Skip to content

Commit cf65302

Browse files
danxmoranpasha-codefreshpasha
authored
Add support for repository dispatch notifications to GitHub service. (#393)
* Add support for repository dispatch notifications to GitHub service. Part of #356 Repository dispatch allows for triggering GitHub Actions via event type (as opposed to "workflow dispatch", which requires specifying a specific workflow to trigger). The triggering calls can pass arbitrary data via "client_payload" JSON. API docs here: https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-dispatch-event Signed-off-by: Daniel Moran <[email protected]> * refactor(tests): replace assert with require for error handling and update map types to 'any' - Updated test cases in github_test.go to use require.NoError for better error handling. - Changed map types from map[string]interface{} to map[string]any for improved type safety. - Replaced assert.Equal with assert.JSONEq for comparing JSON strings in tests. - Cleaned up unnecessary lines in github.go. This refactor enhances code readability and consistency across test cases. --------- Signed-off-by: Daniel Moran <[email protected]> Co-authored-by: Pasha Kostohrys <[email protected]> Co-authored-by: pasha <[email protected]>
1 parent f859d51 commit cf65302

File tree

2 files changed

+129
-5
lines changed

2 files changed

+129
-5
lines changed

pkg/services/github.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package services
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"net/http"
@@ -41,6 +42,7 @@ type GitHubNotification struct {
4142
RepoURLPath string `json:"repoURLPath,omitempty"`
4243
RevisionPath string `json:"revisionPath,omitempty"`
4344
CheckRun *GitHubCheckRun `json:"checkRun,omitempty"`
45+
RepositoryDispatch *GitHubRepositoryDispatch `json:"repositoryDispatch,omitempty"`
4446
}
4547

4648
type GitHubStatus struct {
@@ -82,6 +84,11 @@ type GitHubPullRequestComment struct {
8284
CommentTag string `json:"commentTag,omitempty"`
8385
}
8486

87+
type GitHubRepositoryDispatch struct {
88+
EventType string `json:"event_type,omitempty"`
89+
ClientPayload string `json:"client_payload,omitempty"`
90+
}
91+
8592
const (
8693
repoURLtemplate = "{{.app.spec.source.repoURL}}"
8794
revisionTemplate = "{{.app.status.operationState.syncResult.revision}}"
@@ -204,6 +211,17 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
204211
}
205212
}
206213

214+
var repoDispatchEventType, repoDispatchClientPayload *texttemplate.Template
215+
if g.RepositoryDispatch != nil {
216+
repoDispatchEventType, err = texttemplate.New(name).Funcs(f).Parse(g.RepositoryDispatch.EventType)
217+
if err != nil {
218+
return nil, err
219+
}
220+
repoDispatchClientPayload, err = texttemplate.New(name).Funcs(f).Parse(g.RepositoryDispatch.ClientPayload)
221+
if err != nil {
222+
return nil, err
223+
}
224+
}
207225
return func(notification *Notification, vars map[string]any) error {
208226
if notification.GitHub == nil {
209227
notification.GitHub = &GitHubNotification{
@@ -375,6 +393,20 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
375393
notification.GitHub.CheckRun.Output.Text = textData.String()
376394
}
377395

396+
if g.RepositoryDispatch != nil {
397+
notification.GitHub.RepositoryDispatch = &GitHubRepositoryDispatch{}
398+
var eventTypeData bytes.Buffer
399+
if err := repoDispatchEventType.Execute(&eventTypeData, vars); err != nil {
400+
return err
401+
}
402+
notification.GitHub.RepositoryDispatch.EventType = eventTypeData.String()
403+
var clientPayloadData bytes.Buffer
404+
if err := repoDispatchClientPayload.Execute(&clientPayloadData, vars); err != nil {
405+
return err
406+
}
407+
notification.GitHub.RepositoryDispatch.ClientPayload = clientPayloadData.String()
408+
}
409+
378410
return nil
379411
}, nil
380412
}
@@ -447,6 +479,7 @@ type repositoriesService interface {
447479
ListDeployments(ctx context.Context, owner, repo string, opts *github.DeploymentsListOptions) ([]*github.Deployment, *github.Response, error)
448480
CreateDeployment(ctx context.Context, owner, repo string, request *github.DeploymentRequest) (*github.Deployment, *github.Response, error)
449481
CreateDeploymentStatus(ctx context.Context, owner, repo string, deploymentID int64, request *github.DeploymentStatusRequest) (*github.DeploymentStatus, *github.Response, error)
482+
Dispatch(ctx context.Context, owner, repo string, opts github.DispatchRequestOptions) (*github.Repository, *github.Response, error)
450483
}
451484

452485
type checksService interface {
@@ -699,5 +732,21 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
699732
}
700733
}
701734

735+
if notification.GitHub.RepositoryDispatch != nil {
736+
payload := json.RawMessage(notification.GitHub.RepositoryDispatch.ClientPayload)
737+
_, _, err := g.client.GetRepositories().Dispatch(
738+
context.Background(),
739+
u[0],
740+
u[1],
741+
github.DispatchRequestOptions{
742+
EventType: notification.GitHub.RepositoryDispatch.EventType,
743+
ClientPayload: &payload,
744+
},
745+
)
746+
if err != nil {
747+
return err
748+
}
749+
}
750+
702751
return nil
703752
}

pkg/services/github_test.go

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,48 @@ func TestGetTemplater_Github_PullRequestComment(t *testing.T) {
248248
assert.Equal(t, "This is a comment", notification.GitHub.PullRequestComment.Content)
249249
}
250250

251+
func TestGetTemplater_Github_RepositoryDispatch(t *testing.T) {
252+
n := Notification{
253+
GitHub: &GitHubNotification{
254+
RepoURLPath: "{{.sync.spec.git.repo}}",
255+
RevisionPath: "{{.sync.status.lastSyncedCommit}}",
256+
RepositoryDispatch: &GitHubRepositoryDispatch{
257+
EventType: "sync",
258+
ClientPayload: `{ "sha": "{{.sync.status.lastSyncedCommit}}" }`,
259+
},
260+
},
261+
}
262+
templater, err := n.GetTemplater("", template.FuncMap{})
263+
264+
require.NoError(t, err)
265+
266+
var notification Notification
267+
err = templater(&notification, map[string]any{
268+
"sync": map[string]any{
269+
"metadata": map[string]any{
270+
"name": "root-sync-test",
271+
},
272+
"spec": map[string]any{
273+
"git": map[string]any{
274+
"repo": "https://github.com/argoproj-labs/argocd-notifications.git",
275+
},
276+
},
277+
"status": map[string]any{
278+
"lastSyncedCommit": "0123456789",
279+
},
280+
},
281+
})
282+
283+
require.NoError(t, err)
284+
285+
assert.Equal(t, "{{.sync.spec.git.repo}}", notification.GitHub.RepoURLPath)
286+
assert.Equal(t, "{{.sync.status.lastSyncedCommit}}", notification.GitHub.RevisionPath)
287+
assert.Equal(t, "https://github.com/argoproj-labs/argocd-notifications.git", notification.GitHub.repoURL)
288+
assert.Equal(t, "0123456789", notification.GitHub.revision)
289+
assert.Equal(t, "sync", notification.GitHub.RepositoryDispatch.EventType)
290+
assert.JSONEq(t, `{ "sha": "0123456789" }`, notification.GitHub.RepositoryDispatch.ClientPayload)
291+
}
292+
251293
func TestGetTemplater_Github_PullRequestCommentWithTag(t *testing.T) {
252294
n := Notification{
253295
GitHub: &GitHubNotification{
@@ -340,7 +382,9 @@ type mockPullRequestsService struct {
340382
prs []*github.PullRequest
341383
}
342384

343-
type mockRepositoriesService struct{}
385+
type mockRepositoriesService struct {
386+
dispatches []github.DispatchRequestOptions
387+
}
344388

345389
func (m *mockRepositoriesService) CreateStatus(_ context.Context, _, _, _ string, status *github.RepoStatus) (*github.RepoStatus, *github.Response, error) {
346390
return status, nil, nil
@@ -358,6 +402,11 @@ func (m *mockRepositoriesService) CreateDeploymentStatus(_ context.Context, _, _
358402
return &github.DeploymentStatus{}, nil, nil
359403
}
360404

405+
func (m *mockRepositoriesService) Dispatch(_ context.Context, _, _ string, request github.DispatchRequestOptions) (*github.Repository, *github.Response, error) {
406+
m.dispatches = append(m.dispatches, request)
407+
return &github.Repository{}, nil, nil
408+
}
409+
361410
type mockChecksService struct{}
362411

363412
func (m *mockChecksService) CreateCheckRun(_ context.Context, _, _ string, _ github.CreateCheckRunOptions) (*github.CheckRun, *github.Response, error) {
@@ -377,20 +426,46 @@ func (m *mockGitHubClientImpl) GetPullRequests() pullRequestsService { return m.
377426
func (m *mockGitHubClientImpl) GetRepositories() repositoriesService { return m.repos }
378427
func (m *mockGitHubClientImpl) GetChecks() checksService { return m.checks }
379428

380-
func setupMockServices() (*mockIssuesService, *mockPullRequestsService, githubClient) {
429+
func setupMockServices() (*mockIssuesService, *mockPullRequestsService, *mockRepositoriesService, githubClient) {
381430
issues := &mockIssuesService{comments: []*github.IssueComment{}}
382431
pulls := &mockPullRequestsService{prs: []*github.PullRequest{{Number: github.Ptr(1)}}}
432+
repos := &mockRepositoriesService{}
383433
client := &mockGitHubClientImpl{
384434
issues: issues,
385435
prs: pulls,
386-
repos: &mockRepositoriesService{},
436+
repos: repos,
387437
checks: &mockChecksService{},
388438
}
389-
return issues, pulls, client
439+
return issues, pulls, repos, client
440+
}
441+
442+
func TestGitHubService_Send_RepositoryDispatch(t *testing.T) {
443+
_, _, repos, client := setupMockServices()
444+
445+
service := &gitHubService{client: client}
446+
447+
err := service.Send(Notification{
448+
GitHub: &GitHubNotification{
449+
repoURL: "https://github.com/owner/repo",
450+
revision: "abc123",
451+
RepositoryDispatch: &GitHubRepositoryDispatch{
452+
EventType: "sync",
453+
ClientPayload: `{ "sha": "12345678" }`,
454+
},
455+
},
456+
}, Destination{})
457+
458+
require.NoError(t, err)
459+
assert.Len(t, repos.dispatches, 1)
460+
assert.Equal(t, "sync", repos.dispatches[0].EventType)
461+
462+
payload, err := repos.dispatches[0].ClientPayload.MarshalJSON()
463+
require.NoError(t, err)
464+
assert.JSONEq(t, `{ "sha": "12345678" }`, string(payload))
390465
}
391466

392467
func TestGitHubService_Send_PullRequestCommentWithTag(t *testing.T) {
393-
issues, _, client := setupMockServices()
468+
issues, _, _, client := setupMockServices()
394469

395470
service := &gitHubService{client: client}
396471

0 commit comments

Comments
 (0)