Browse Source

initial commit

Signed-off-by: Erik Hollensbe <github@hollensbe.org>
master
Erik Hollensbe 3 years ago
commit
1e48bb5358
  1. 3
      README.md
  2. 12
      go.mod
  3. 27
      go.sum
  4. 176
      tissue.go

3
README.md

@ -0,0 +1,3 @@
I'm itchy.
You can go get this and it works

12
go.mod

@ -0,0 +1,12 @@
module github.com/erikh/tissue
require (
github.com/codegangsta/cli v1.20.0 // indirect
github.com/fatih/color v1.7.0
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/urfave/cli v1.20.0
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
)

27
go.sum

@ -0,0 +1,27 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/codegangsta/cli v1.20.0 h1:iX1FXEgwzd5+XN6wk5cVHOGQj6Q3Dcp20lUeS4lHNTw=
github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

176
tissue.go

@ -0,0 +1,176 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"github.com/fatih/color"
"github.com/google/go-github/github"
"github.com/urfave/cli"
"golang.org/x/oauth2"
)
func main() {
app := cli.NewApp()
app.Name = "tissue"
app.Description = `
tissue lets you transfer issues to and from github repositories. The
repositories do not necessarily need to be where the archive originated;
allowing you to clone issues between repositories.
It currently will not clone:
* Labels
* Milestones
Because of the additional complications with creating those items.
`
app.Usage = "Archive and Restore Github Issues"
app.Author = "Erik Hollensbe <github@hollensbe.org>"
app.Version = "the last one"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "token, t",
Usage: "The github token to use for the transfer",
EnvVar: "GITHUB_TOKEN",
},
cli.StringFlag{
Name: "repository, r",
Usage: "The repository to transfer; in owner/repo syntax.",
},
cli.BoolFlag{
Name: "open, o",
Usage: "Only capture open state issues",
},
}
app.Commands = []cli.Command{
{
Name: "to",
Usage: "Transfer a JSON blob as issues into the repository",
Description: `
Transferring to a repository requires a tissue-compatible backup, generated
with 'tissue from'.
`,
Action: to,
},
{
Name: "from",
Usage: "Transfer a JSON blob from a repository, containing its issues",
Description: `
Generates a backup suitable for transferring to a new github repository with 'tissue to'.
`,
Action: from,
},
}
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func mkRepo(ctx *cli.Context) (string, string, error) {
repo := ctx.GlobalString("repository")
parts := strings.SplitN(strings.TrimSpace(repo), "/", 2)
if len(parts) != 2 {
return "", "", fmt.Errorf("invalid repository name %v", repo)
}
if strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" {
return "", "", fmt.Errorf("components of repository name %v are missing", repo)
}
return parts[0], parts[1], nil
}
func argCheck(ctx *cli.Context) (string, string, error) {
if strings.TrimSpace(ctx.GlobalString("token")) == "" {
return "", "", errors.New("no token -- seek help")
}
return mkRepo(ctx)
}
func to(ctx *cli.Context) error {
owner, repo, err := argCheck(ctx)
if err != nil {
return err
}
tok := &oauth2.Token{AccessToken: ctx.GlobalString("token")}
client := github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(tok)))
var totalIssues []*github.Issue
if err := json.NewDecoder(os.Stdin).Decode(&totalIssues); err != nil {
return err
}
for _, issue := range totalIssues {
color.New(color.FgWhite).Printf("Injecting issue for #%d: %q ...", issue.GetNumber(), issue.GetTitle())
assn := []string{}
for _, ass := range issue.Assignees {
assn = append(assn, ass.GetLogin())
}
_, _, err := client.Issues.Create(context.Background(), owner, repo, &github.IssueRequest{
Title: issue.Title,
Body: issue.Body,
State: issue.State,
Assignees: &assn,
})
if err != nil {
return err
}
color.New(color.FgGreen).Println("done")
}
return nil
}
func from(ctx *cli.Context) error {
owner, repo, err := argCheck(ctx)
if err != nil {
return err
}
tok := &oauth2.Token{AccessToken: ctx.GlobalString("token")}
client := github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(tok)))
var i int
totalIssues := []*github.Issue{}
for {
issues, _, err := client.Issues.ListByRepo(context.Background(), owner, repo, &github.IssueListByRepoOptions{ListOptions: github.ListOptions{Page: i, PerPage: 200}})
if err != nil {
return err
}
if len(issues) == 0 {
break
}
if ctx.GlobalBool("open") {
for _, issue := range issues {
if issue.GetState() == "open" {
totalIssues = append(totalIssues, issue)
}
}
} else {
totalIssues = append(totalIssues, issues...)
}
i++
}
return json.NewEncoder(os.Stdout).Encode(totalIssues)
}
Loading…
Cancel
Save