Skip to content

Commit

Permalink
Make it a Go app
Browse files Browse the repository at this point in the history
  • Loading branch information
leofeyer committed Mar 17, 2023
1 parent 37a3a12 commit a68a289
Show file tree
Hide file tree
Showing 11 changed files with 457 additions and 142 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: release

on:
push:
tags:
- '*'

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cli/[email protected]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/gh-merge
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,35 @@
`gh merge` is a GitHub CLI extension to squash and merge PRs. The commit
message will be the PR description followed by the list of commits.

## Installation

Make sure you have `gh` and `git` installed. Then run:

```bash
$ gh extension install leofeyer/gh-merge
```

## Usage

```bash
$ gh merge --help
$ gh merge 1234
```

Usage: gh merge {<number>} [options]
If you are on a branch that you have checked out with `gh pr checkout 1234`,
you can omit the PR number:

Options:
-h, --help Display the help information
```bash
$ gh merge
```

## Installation
Use the `--auto` flag to enable auto-merging:

Make sure you have `gh` and `git` installed.
```bash
$ gh merge 1234 --auto
```

Then run:
Use the `--admin` flag to merge the PR with admin privileges:

```bash
$ gh extension install leofeyer/gh-merge
$ gh merge 1234 --admin
```
32 changes: 32 additions & 0 deletions api/get-number.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package api

import (
"encoding/json"
"strconv"

"github.com/cli/go-gh"
)

func GetNumber(args []string) (string, error) {
if len(args) > 0 {
return args[0], nil
}

data, _, err := gh.Exec("pr", "view", "--json", "number")
if err != nil {
return "", err
}

type Result struct {
Number int `json:"number"`
}

var r Result

err = json.Unmarshal(data.Bytes(), &r)
if err != nil {
return "", err
}

return strconv.Itoa(r.Number), nil
}
136 changes: 136 additions & 0 deletions api/merge-pr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package api

import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"

"github.com/cli/go-gh"
"github.com/leofeyer/gh-merge/util"
)

func MergePr(pr string, auto bool, admin bool) error {
subject, err := getSubject(pr)
if err != nil {
return err
}

body, err := getBody(pr)
if err != nil {
return err
}

fmt.Println("")
fmt.Println(body)

prompt := util.Confirm("Merge '"+subject+"' now?", false)
if prompt == false {
return errors.New("Cancelled.")
}

var args []string
args = append(args, "pr", "merge", pr, "--subject", subject, "--body", body, "--squash")

if auto {
args = append(args, "--auto")
}

if admin {
args = append(args, "--admin")
}

data, _, err := gh.Exec(args...)
if err != nil {
return err
}

fmt.Print(data.String())
return nil
}

func getSubject(pr string) (string, error) {
data, _, err := gh.Exec("pr", "view", pr, "--json", "title")
if err != nil {
return "", err
}

type Result struct {
Title string `json:"title"`
}

var r Result

err = json.Unmarshal(data.Bytes(), &r)
if err != nil {
return "", err
}

return fmt.Sprintf("%s (see #%s)", r.Title, pr), nil
}

func getBody(pr string) (string, error) {
data, _, err := gh.Exec("pr", "view", pr, "--json", "author,body,commits")
if err != nil {
return "", err
}

type Result struct {
Author struct {
Login string `json:"login"`
}
Body string `json:"body"`
Commits []struct {
Oid string `json:"oid"`
Headline string `json:"messageHeadline"`
Authors []struct {
Login string `json:"login"`
Email string `json:"email"`
}
}
}

var r Result

err = json.Unmarshal(data.Bytes(), &r)
if err != nil {
return "", err
}

x := regexp.MustCompile("(?s)<!--.*?-->")

ret := "Description\n-----------\n\n"
ret += strings.TrimSpace(x.ReplaceAllString(r.Body, ""))
ret += "\n\nCommits\n-------\n\n"

authors := make(map[string]string)

for i := 0; i < len(r.Commits); i++ {
if r.Commits[i].Headline == "CS" {
continue
}

if strings.HasPrefix(r.Commits[i].Headline, "Merge branch ") {
continue
}

ret += fmt.Sprintf("%.8s", r.Commits[i].Oid) + " " + r.Commits[i].Headline + "\n"

if r.Commits[i].Authors[0].Login == r.Author.Login {
continue
}

authors[r.Commits[i].Authors[0].Login] = r.Commits[i].Authors[0].Email
}

if len(authors) > 0 {
ret += "\n"

for author, email := range authors {
ret += "Co-authored-by: " + author + " <" + email + ">\n"
}
}

return ret, nil
}
70 changes: 70 additions & 0 deletions api/thank-author.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package api

import (
"encoding/json"
"fmt"

"github.com/cli/go-gh"
"github.com/leofeyer/gh-merge/util"
)

func ThankAuthor(pr string) error {
user, err := getUser()
if err != nil {
return err
}

author, err := getAuthor(pr)
if err != nil {
return err
}

// We do not want to thank ourselves
if user == author {
return nil
}

prompt := util.Confirm("Say thank you?", true)
if prompt == false {
return nil
}

data, _, err := gh.Exec("pr", "comment", pr, "--body", "Thank you @"+author+".")
if err != nil {
return err
}

fmt.Print(data.String())
return nil
}

func getUser() (string, error) {
data, _, err := gh.Exec("config", "get", "user", "-h", "github.com")
if err != nil {
return "", err
}

return data.String(), nil
}

func getAuthor(pr string) (string, error) {
data, _, err := gh.Exec("pr", "view", pr, "--json", "author")
if err != nil {
return "", err
}

type Result struct {
Author struct {
Login string `json:"login"`
}
}

var r Result

err = json.Unmarshal(data.Bytes(), &r)
if err != nil {
return "", err
}

return r.Author.Login, nil
}
Loading

0 comments on commit a68a289

Please sign in to comment.