Skip to content

Commit

Permalink
feat: trigger argo-diff from comment
Browse files Browse the repository at this point in the history
  • Loading branch information
vrivellino committed Jan 29, 2024
1 parent ff82621 commit ed2c859
Show file tree
Hide file tree
Showing 8 changed files with 642 additions and 8 deletions.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,8 @@ Below are screenshots of Github Pull Request comments generated by argo-diff.

This is still in a proof-of-concept and alpha/beta version state, so there are some known limitations.

- If there's a problem, and the diff comment needs to be regenerated, an admin must redeliver the webhook
event associated with the PR. In the future, argo-diff may be re-initated by a comment on the PR. [#11]
- Changes to Secrets are _not_ displayed. A future enhancement could flag that secrets are changing without
displaying the contents. [#52]
- Only supports Github Personal Access Tokens at this time. [#14]
- When many Argo applications are served by a single repository, performance may be slow. Manifests for eac
Argo application are fetched sequentially, so this could result in argo-diff statuses and/or comments
taking minutes to complete.
Expand Down
16 changes: 16 additions & 0 deletions internal/process_event/code_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ func ProcessCodeChange(eventInfo webhook.EventInfo, devMode bool, wg *sync.WaitG
defer cancel()

isPr := eventInfo.PrNum > 0
if isPr && eventInfo.Refresh {
pull, err := github.GetPullRequest(ctx, eventInfo.RepoOwner, eventInfo.RepoName, eventInfo.PrNum)
if err != nil {
log.Error().Err(err).Msgf("github.GetPullRequest(%s, %s, %d) failed", eventInfo.RepoOwner, eventInfo.RepoName, eventInfo.PrNum)
return
}
base := pull.GetBase()
head := pull.GetHead()
if base == nil || head == nil {
log.Error().Msgf("Empty branch information when refreshing %s/%s#%d", eventInfo.RepoOwner, eventInfo.RepoName, eventInfo.PrNum)
return
}
eventInfo.Sha = *head.SHA
eventInfo.ChangeRef = *head.Ref
eventInfo.BaseRef = *base.Ref
}

// set commit status to PENDING
github.Status(ctx, isPr, github.StatusPending, "", eventInfo.RepoOwner, eventInfo.RepoName, eventInfo.Sha, devMode)
Expand Down
8 changes: 7 additions & 1 deletion internal/server/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ func (wp *WebhookProcessor) handleWebhook(w http.ResponseWriter, r *http.Request
http.Error(w, "Could not process push event data", http.StatusInternalServerError)
return
}
case "issue_comment":
eventInfo, err = webhook.ProcessComment(payload)
if err != nil {
http.Error(w, "Could not process issue comment data", http.StatusInternalServerError)
return
}
default:
log.Info().Str("method", r.Method).Str("url", r.URL.String()).Msgf("Ignoring X-GitHub-Event %s", event)
_, err := io.WriteString(w, "event ignored\n")
Expand Down Expand Up @@ -155,7 +161,7 @@ func StartWebhookProcessor(host string, port int, webhook_secret string, devMode

wp := WebhookProcessor{
GithubWebhookSecret: webhook_secret,
DevMode: false,
DevMode: devMode,
}

srv := &http.Server{Addr: addr}
Expand Down
44 changes: 42 additions & 2 deletions internal/webhook/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type EventInfo struct {
PrNum int `json:"pr"`
ChangeRef string `json:"change_ref"`
BaseRef string `json:"base_ref"`
Refresh bool `json:"ignore"`
}

func NewEventInfo() EventInfo {
Expand All @@ -32,6 +33,7 @@ func NewEventInfo() EventInfo {
PrNum: -1,
ChangeRef: "",
BaseRef: "",
Refresh: false,
}
}

Expand All @@ -45,10 +47,10 @@ func validateEventInfo(e EventInfo) error {
if e.RepoDefaultRef == "" {
return errors.New("missing default ref in event info object")
}
if e.Sha == "" {
if !e.Refresh && e.Sha == "" {
return errors.New("missing SHA in event info object")
}
if e.ChangeRef == "" {
if !e.Refresh && e.ChangeRef == "" {
return errors.New("missing change ref in event info object")
}
return nil
Expand Down Expand Up @@ -113,3 +115,41 @@ func ProcessPush(payload []byte) (EventInfo, error) {
log.Debug().Msgf("Returning EventInfo: %+v", pushInfo)
return pushInfo, validateEventInfo(pushInfo)
}

// Processes a comment created event received from github
func ProcessComment(payload []byte) (EventInfo, error) {
prInfo := NewEventInfo()
var commentEvent github.IssueCommentEvent
if err := json.Unmarshal(payload, &commentEvent); err != nil {
log.Error().Err(err).Msg("Error decoding JSON payload")
return prInfo, err
}
if action := commentEvent.GetAction(); action != "created" {
log.Info().Msgf("Ignoring issue comment event with action %s", action)
return prInfo, nil
}
issue := commentEvent.GetIssue()
issueComment := commentEvent.GetComment()
repo := commentEvent.GetRepo()
if issue == nil || issueComment == nil || repo == nil {
log.Warn().Msg("Ignoring issue comment event with missing field(s)")
return prInfo, nil
}
if issue.PullRequestLinks == nil {
log.Info().Msg("Ignoring non-pull issue comment")
return prInfo, nil
}
prInfo.PrNum = *issue.Number
prInfo.RepoOwner = *repo.Owner.Login
prInfo.RepoName = *repo.Name
prInfo.RepoDefaultRef = *repo.DefaultBranch
// TODO ToLower() and look at context string
if issueComment.Body == nil || strings.TrimSpace(*issueComment.Body) != "argo diff" {
log.Info().Msg("Ignoring pull request comment")
return prInfo, nil
}
prInfo.Ignore = false
prInfo.Refresh = true
log.Debug().Msgf("Returning EventInfo: %+v", prInfo)
return prInfo, validateEventInfo(prInfo)
}
47 changes: 47 additions & 0 deletions internal/webhook/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const payloadPushBranchDelete = "payload-push-branch-delete.json"
const payloadPushBranchDev = "payload-push-branch-dev.json"
const payloadPushBranchMain = "payload-push-branch-main.json"
const payloadPushTag = "payload-push-tag.json"
const payloadCommentCreated = "payload-comment-created.json"
const payloadCommentCreatedArgoDiff = "payload-comment-argodiff-created.json"

func readFileToByteArray(fileName string) ([]byte, string, error) {
workingDir, err := os.Getwd()
Expand Down Expand Up @@ -60,6 +62,9 @@ func TestLoadPullRequestEvents(t *testing.T) {
if result.RepoDefaultRef == result.ChangeRef {
t.Errorf("ProcessPullRequest() ChangeRef is the same as DefaultRef")
}
if result.Refresh {
t.Errorf("ProcessPullRequest() Expected to NOT set refresh flag. Payload %s", filePath)
}
}
}
}
Expand Down Expand Up @@ -107,6 +112,9 @@ func TestLoadPushEvents(t *testing.T) {
t.Errorf("ProcessPushRequest() Result has at least one empty value: %+v; Payload %s", result, filePath)
}
}
if result.Refresh {
t.Errorf("ProcessPushRequest() Expected to NOT set refresh flag. Payload %s", filePath)
}
}
}

Expand All @@ -124,3 +132,42 @@ func TestLoadNotAPushEvent(t *testing.T) {
t.Errorf("ProcessPushRequest() Bad event %s should have been ignored", filePath)
}
}

func TestLoadCommentEvent(t *testing.T) {
var result EventInfo
// const payloadCommentCreated = "payload-comment-created.json"
// const payloadCommentCreatedArgoDiff = "payload-comment-argodiff-created.json"
payloadFiles := []string{payloadCommentCreated, payloadCommentCreatedArgoDiff}
for _, payloadFile := range payloadFiles {
payload, filePath, err := readFileToByteArray(payloadFile)
if err != nil {
t.Errorf("Failed to read %s: %v", payloadFile, err)
}
if err != nil {
t.Errorf("Failed to read %s: %v", payloadCommentCreated, err)
}
result, err = ProcessComment(payload)
if err != nil {
t.Errorf("Failed to load payload from %s: %v", filePath, err)
}
if result.RepoOwner == "" || result.RepoName == "" || result.RepoDefaultRef == "" || result.PrNum < 1 {
t.Errorf("ProcessComment() Result has at least one empty value: %+v; Payload %s", result, filePath)
}
if payloadFile == payloadCommentCreated {
if !result.Ignore {
t.Errorf("ProcessComment() Expected to ignore this event. Payload %s", filePath)
}
if result.Refresh {
t.Errorf("ProcessComment() Expected to NOT set refresh flag. Payload %s", filePath)
}
}
if payloadFile == payloadCommentCreatedArgoDiff {
if result.Ignore {
t.Errorf("ProcessComment() Expected to NOT ignore this event. Payload %s", filePath)
}
if !result.Refresh {
t.Errorf("ProcessComment() Expected to set refresh flag. Payload %s", filePath)
}
}
}
}
Loading

0 comments on commit ed2c859

Please sign in to comment.