Skip to content

Commit

Permalink
fix nits
Browse files Browse the repository at this point in the history
  • Loading branch information
sailorlqh committed Jul 20, 2023
1 parent a40ce96 commit f2d510a
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 44 deletions.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module github.com/drevell/hackathon

go 1.20

require github.com/abcxyz/pkg v0.3.0
require (
github.com/abcxyz/pkg v0.3.0
github.com/google/go-cmp v0.5.9
)

require (
github.com/kr/text v0.1.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/goccy/go-json v0.10.1 h1:lEs5Ob+oOG/Ze199njvzHbhn6p9T+h64F5hRj69iTTo=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
Expand Down
86 changes: 43 additions & 43 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"github.com/abcxyz/pkg/cli"
Expand Down Expand Up @@ -48,14 +50,32 @@ Usage: {{ COMMAND }} [options]
`
}

var rootCmd = func() cli.Command {
return &cli.RootCommand{
Name: "send-google-chat-webhook",
Commands: map[string]cli.CommandFactory{
"chat": func() cli.Command {
return &cli.RootCommand{
Name: "workflownotification",
Description: "notification for workflow",
Commands: map[string]cli.CommandFactory{
"workflownotification": func() cli.Command {
return &WorkflowNotificationCommand{}
},
},
}
},
},
}
}

func (c *WorkflowNotificationCommand) Flags() *cli.FlagSet {
set := cli.NewFlagSet()

f := set.NewSection("Chat space options")

f.StringVar(&cli.StringVar{
Name: "webhook_url",
Aliases: []string{"w"},
Name: "webhook-url",
Example: "https://chat.goog...",
Default: "",
Target: &c.flagWebhookUrl,
Expand Down Expand Up @@ -94,70 +114,50 @@ func (c *WorkflowNotificationCommand) Run(ctx context.Context, args []string) er
return fmt.Errorf("failed unmarshaling %s: %w", jobContextEnv, err)
}

b, err := messageBody(ghJson, jobJson)
b, err := generateMessageBody(ghJson, jobJson, time.Now())
if err != nil {
return fmt.Errorf("failed to generate message body: %w", err)
}

url := c.flagWebhookUrl
fmt.Println("url: ", url)

request, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
request, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(b))
if err != nil {
return fmt.Errorf("creating http request failed: %w", err)
}
resp, err := http.DefaultClient.Do(request)

client := http.Client{}
resp, err := client.Do(request)
if err != nil {
return fmt.Errorf("sending http request failed: %w", err)
}
fmt.Println("resp: ", resp)

defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected HTTP status code %d (%s)", resp.StatusCode, http.StatusText(resp.StatusCode))
}

return nil
}

func main() {
if err := realMain(); err != nil {
ctx, done := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer done()

if err := realMain(ctx); err != nil {
done()
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
}

func realMain() error {
rootCmd := func() cli.Command {
return &cli.RootCommand{
Name: "send-google-chat-webhook",
Commands: map[string]cli.CommandFactory{
"chat": func() cli.Command {
return &cli.RootCommand{
Name: "workflownotification",
Description: "notification for workflow",
Commands: map[string]cli.CommandFactory{
"workflownotification": func() cli.Command {
return &WorkflowNotificationCommand{}
},
},
}
},
},
}
}

cmd := rootCmd()
// Help output is written to stderr by default. Redirect to stdout so the
// "Output" assertion works.
cmd.SetStderr(os.Stdout)

ctx := context.Background()
err := cmd.Run(ctx, os.Args[1:])
if err != nil {
return fmt.Errorf("failed to run command: %w", err)
}

return nil
func realMain(ctx context.Context) error {
return rootCmd().Run(ctx, os.Args[1:]) //nolint:wrapcheck // Want passthrough
}

func messageBody(ghJson, jobJson map[string]any) ([]byte, error) {
func generateMessageBody(ghJson, jobJson map[string]any, timestamp time.Time) ([]byte, error) {
timezoneLoc, _ := time.LoadLocation("America/Los_Angeles")

var iconUrl string
Expand Down Expand Up @@ -204,15 +204,15 @@ func messageBody(ghJson, jobJson map[string]any) ([]byte, error) {
"startIcon": map[string]any{
"knownIcon": "CLOCK",
},
"text": fmt.Sprintf("<b>Pacific:</b> %s", time.Now().In(timezoneLoc).Format(time.DateTime)),
"text": fmt.Sprintf("<b>Pacific:</b> %s", timestamp.In(timezoneLoc).Format(time.DateTime)),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "CLOCK",
},
"text": fmt.Sprintf("<b>UTC:</b> %s", time.Now().UTC().Format(time.DateTime)),
"text": fmt.Sprintf("<b>UTC:</b> %s", timestamp.UTC().Format(time.DateTime)),
},
},
{
Expand Down
207 changes: 207 additions & 0 deletions src/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package main

import (
"encoding/json"
"fmt"
"testing"
"time"

"github.com/google/go-cmp/cmp"
)

func TestGenerateMessageBody(t *testing.T) {
t.Parallel()

cases := []struct {
name string
ghJson map[string]any
jobJson map[string]any
timestamp time.Time
location time.Location
wantMessageBody map[string]any
}{
{
name: "test_success_workflow",
ghJson: map[string]any{
"workflow": "test-workflow",
"ref": "test-ref",
"triggering_actor": "test-triggered_actor",
"repository": "test-repository",
"run_id": "test-run-id",
},
jobJson: map[string]any{
"status": "success",
},
timestamp: time.Date(2023, time.April, 25, 17, 44, 57, 0, time.UTC),
wantMessageBody: map[string]any{
"cardsV2": map[string]any{
"cardId": "createCardMessage",
"card": map[string]any{
"header": map[string]any{
"title": fmt.Sprintf("GitHub workflow %s", "success"),
"subtitle": fmt.Sprintf("Workflow: <b>%s</b>", "test-workflow"),
"imageUrl": "https://github.githubassets.com/favicons/favicon.png",
},
"sections": []any{
map[string]any{
"collapsible": true,
"uncollapsibleWidgetsCount": float64(1),
"widgets": []map[string]any{
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"iconUrl": "https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/quick_reference/default/48px.svg",
},
"text": fmt.Sprintf("<b>Ref:</b> %s", "test-ref"),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "PERSON",
},
"text": fmt.Sprintf("<b>Run by:</b> %s", "test-triggered_actor"),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "CLOCK",
},
"text": fmt.Sprintf("<b>Pacific:</b> %s", time.Date(2023, time.April, 25, 17, 44, 57, 0, time.UTC).In(time.FixedZone("UTC-8", -7*60*60)).Format(time.DateTime)),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "CLOCK",
},
"text": fmt.Sprintf("<b>UTC:</b> %s", time.Date(2023, time.April, 25, 17, 44, 57, 0, time.UTC).UTC().Format(time.DateTime)),
},
},
{
"buttonList": map[string]any{
"buttons": []any{
map[string]any{
"text": "Open",
"onClick": map[string]any{
"openLink": map[string]any{
"url": fmt.Sprintf("https://github.com/%s/actions/runs/%s",
"test-repository", "test-run-id"),
},
},
},
},
},
},
},
},
},
},
},
},
},
{
name: "test_failed_workflow",
ghJson: map[string]any{
"workflow": "test-workflow",
"ref": "test-ref",
"triggering_actor": "test-triggered_actor",
"repository": "test-repository",
"run_id": "test-run-id",
},
jobJson: map[string]any{
"status": "xxx",
},
timestamp: time.Date(2023, time.April, 25, 17, 44, 57, 0, time.UTC),
wantMessageBody: map[string]any{
"cardsV2": map[string]any{
"cardId": "createCardMessage",
"card": map[string]any{
"header": map[string]any{
"title": fmt.Sprintf("GitHub workflow %s", "xxx"),
"subtitle": fmt.Sprintf("Workflow: <b>%s</b>", "test-workflow"),
"imageUrl": "https://github.githubassets.com/favicons/favicon-failure.png",
},
"sections": []any{
map[string]any{
"collapsible": true,
"uncollapsibleWidgetsCount": float64(1),
"widgets": []map[string]any{
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"iconUrl": "https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/quick_reference/default/48px.svg",
},
"text": fmt.Sprintf("<b>Ref:</b> %s", "test-ref"),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "PERSON",
},
"text": fmt.Sprintf("<b>Run by:</b> %s", "test-triggered_actor"),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "CLOCK",
},
"text": fmt.Sprintf("<b>Pacific:</b> %s", time.Date(2023, time.April, 25, 17, 44, 57, 0, time.UTC).In(time.FixedZone("UTC-8", -7*60*60)).Format(time.DateTime)),
},
},
{
"decoratedText": map[string]any{
"startIcon": map[string]any{
"knownIcon": "CLOCK",
},
"text": fmt.Sprintf("<b>UTC:</b> %s", time.Date(2023, time.April, 25, 17, 44, 57, 0, time.UTC).UTC().Format(time.DateTime)),
},
},
{
"buttonList": map[string]any{
"buttons": []any{
map[string]any{
"text": "Open",
"onClick": map[string]any{
"openLink": map[string]any{
"url": fmt.Sprintf("https://github.com/%s/actions/runs/%s",
"test-repository", "test-run-id"),
},
},
},
},
},
},
},
},
},
},
},
},
},
}

for _, tc := range cases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
gotMessageBody, err := generateMessageBody(tc.ghJson, tc.jobJson, tc.timestamp)
if err != nil {
t.Fatalf("failed to generate messag body %v", err)
}

wantMessageBodyByte, err := json.Marshal(tc.wantMessageBody)
if err != nil {
t.Fatalf("failed to marshal tc.wantMessageBody: %v", err)
}

if diff := cmp.Diff(wantMessageBodyByte, gotMessageBody); diff != "" {
t.Errorf("messageBody got unexpected diff (-want, +got):\n%s", diff)
}

})
}
}

0 comments on commit f2d510a

Please sign in to comment.