diff options
author | Gabriel A. Giovanini <g.giovanini@gridx.de> | 2023-04-27 11:29:53 +0200 |
---|---|---|
committer | Gabriel A. Giovanini <g.giovanini@gridx.de> | 2023-11-07 11:33:04 +0100 |
commit | 4246ea81d56c93c1df2954e34cc33fb6e6524f49 (patch) | |
tree | f6ce5b4a65648a10897029777f79916f1803ddfd | |
download | workctl-4246ea81d56c93c1df2954e34cc33fb6e6524f49.tar.gz workctl-4246ea81d56c93c1df2954e34cc33fb6e6524f49.tar.bz2 workctl-4246ea81d56c93c1df2954e34cc33fb6e6524f49.zip |
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | go.mod | 11 | ||||
-rw-r--r-- | go.sum | 8 | ||||
-rw-r--r-- | main.go | 169 | ||||
-rw-r--r-- | main_test.go | 127 |
6 files changed, 335 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..07d33df --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +PREFIX?=/usr/local +OUTPUT?=bin/workctl + +all: build + +install: build + install -m755 $(OUTPUT) $(PREFIX)/bin/workctl + +build: + go build -v -o $(OUTPUT) . + +test: + go test -v ./... + +run: + go run -v . + +tiny: + tinygo build . @@ -0,0 +1,11 @@ +module git.sr.ht/~gabrielgio/workctl + +go 1.20 + +require github.com/urfave/cli/v2 v2.25.1 + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect +) @@ -0,0 +1,8 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw= +github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= @@ -0,0 +1,169 @@ +package main + +import ( + "fmt" + "io" + "os" + "os/exec" + "regexp" +) + +const ( + prLinkRegex = `https://github.com/.+/.+/(pull|issues)/[0-9]*` + version = "0.0.1" +) + +var ( + prRegex = regexp.MustCompile(prLinkRegex) +) + +func extractPRLink(text string) string { + return prRegex.FindString(text) +} + +func getLinkFromSTDIn() (string, error) { + in, err := io.ReadAll(os.Stdin) + if err != nil { + return "", err + } + + if err != nil { + return "", err + } + + prLink := extractPRLink(string(in)) + if prLink == "" { + return "", fmt.Errorf("Unable to find link") + } + + return prLink, nil +} + +func pipeTo(app string, args ...string) error { + prLink, err := getLinkFromSTDIn() + if err != nil { + return err + } + + args = append(args, prLink) + + _, err = execCommand(app, args...) + return err +} + +func execCommand(app string, args ...string) (string, error) { + cmd := exec.Command(app, args...) + stdout, err := cmd.Output() + + if err != nil { + return "", err + } + + return string(stdout), nil +} + +func shellIn(app string, args ...string) error { + cmd := exec.Command(app, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + + return cmd.Run() +} + +func merge() error { + return pipeTo("gh", "pr", "merge", "--merge") +} + +func approve() error { + return pipeTo("gh", "pr", "review", "--approve") +} + +func dependabot() error { + return pipeTo("gh", "pr", "comment", "--body", "@dependabot rebase\n@dependabot merge") +} + +func open() error { + return pipeTo("qutebrowser", "-l", "critical") +} + +func edit() error { + file, err := os.CreateTemp("", "workctl") + if err != nil { + return err + } + defer file.Close() + defer os.Remove(file.Name()) + + prLink, err := getLinkFromSTDIn() + if err != nil { + return err + } + + out, err := execCommand("gh", "pr", "diff", "--patch", prLink) + if err != nil { + return err + } + + _, err = file.WriteString(out) + if err != nil { + return err + } + + return shellIn("nvim", "-c", "setlocal filetype=gitcommit", file.Name()) +} + +func printVersion() { + fmt.Print("workctl ", version) +} + +func help() { + fmt.Printf(`workctl %s +Extract a general link from a given "text/plain" email from github and append +it to another commands. + +USAGE: + workctl [COMMAND] + +COMMAND: + vimfy edit a file with vim and trim breaking lines so it fits textboxes with easy + open open a given link on qutebrowser + merge issue a merge request for a given link + approve approve PR from a given link + dependabot comment dependabot to rebase and merge for given link + edit open the patch file from a given link`, version) +} + +func printIfError(err error) { + if err != nil { + fmt.Println("Error running the command:") + fmt.Println(err.Error()) + os.Exit(1) + } +} + +func main() { + if len(os.Args) > 2 { + fmt.Println("Invalid number of param") + help() + os.Exit(1) + } + + action := os.Args[1] + + switch action { + case "open": + printIfError(open()) + case "merge": + printIfError(merge()) + case "edit": + printIfError(edit()) + case "approve": + printIfError(approve()) + case "dependabot": + printIfError(dependabot()) + case "version", "--version": + printVersion() + default: + help() + } +} diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..6d0d59f --- /dev/null +++ b/main_test.go @@ -0,0 +1,127 @@ +//go:build unit + +package main + +import ( + "testing" +) + +func TestExtractPR(t *testing.T) { + + testCases := []struct { + name string + mail string + want string + }{ + { + name: "pr created", + want: "https://github.com/grid-x/dploy/pull/9", + mail: `This will allow the change log to directly link the PR making a bit easier to check the summary of those PR. + +Ex.: + + + +You can view, comment on, or merge this pull request online at: + + https://github.com/grid-x/dploy/pull/9 + +-- Commit Summary -- + + * feat(main): allow link pr instead of message + +-- File Changes -- + + M main.go (61) + +-- Patch Links -- + +https://github.com/grid-x/dploy/pull/9.patch +https://github.com/grid-x/dploy/pull/9.diff + +-- +Reply to this email directly or view it on GitHub: +https://github.com/grid-x/dploy/pull/9 +You are receiving this because you are subscribed to this thread. + +Message ID: <grid-x/dploy/pull/9@github.com>`, + }, + { + name: "request review", + want: "https://github.com/grid-x/edge-connector/pull/319", + mail: `@juliusmh requested review from @grid-x/edge-connector-team on: grid-x/edge-connector#319 fix(api/manage): write system controls to response after set as a code owner. + +-- +Reply to this email directly or view it on GitHub: +https://github.com/grid-x/edge-connector/pull/319#event-9104760420 +You are receiving this because your review was requested. + +Message ID: <grid-x/edge-connector/pull/319/issue_event/9104760420@github.com>`, + }, + { + name: "pr merged", + want: "https://github.com/grid-x/edge-connector/pull/319", + mail: `Merged #319 into main. + +-- +Reply to this email directly or view it on GitHub: +https://github.com/grid-x/edge-connector/pull/319#event-9112252051 +You are receiving this because your review was requested. + +Message ID: <grid-x/edge-connector/pull/319/issue_event/9112252051@github.com>`, + }, + { + name: "pr pushed", + want: "https://github.com/grid-x/edge-connector/pull/313", + mail: `@juliusmh pushed 1 commit. + +a0557c770be6d9c2b6070c4fd6a69c68c5e3996f feat(feature/service): accept feature names in kebab-case + +-- +View it on GitHub: +https://github.com/grid-x/edge-connector/pull/313/files/dfdd5081691056150ace71dfb5d11265593c561e..a0557c770be6d9c2b6070c4fd6a69c68c5e3996f +You are receiving this because you are subscribed to this thread. + +Message ID: <grid-x/edge-connector/pull/313/push/13418764381@github.com>`, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + prLink := extractPRLink(tc.mail) + + if prLink != tc.want { + t.Error("Invalid link returned: " + prLink) + } + }) + } +} + +func TestExec(t *testing.T) { + testCases := []struct { + name string + app string + args []string + want string + }{ + { + name: "echo", + app: "echo", + args: []string{"this", "is", "a", "phrase"}, + want: "this is a phrase\n", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + out, err := execCommand(tc.app, tc.args...) + if err != nil { + t.Fatal("Failed " + err.Error()) + } + + if out != tc.want { + t.Error("Invalid stdout returned: " + out) + } + }) + } +} |