Signed-off-by: jman <srht@city17.xyz>
---
README.md | 10 ++++-
main.go | 121 +++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 93 insertions(+), 38 deletions(-)
diff --git a/README.md b/README.md
index 4a5043b..f79027f 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,15 @@ A tool to migrate from GitHub to SourceHut.
Only todo.sr.ht is supported for now.
export GITHUB_TOKEN=<token>
- go run . <repo> | gzip >todo.json.gz
+ go run . [<repo_owner>] <repo> | gzip >todo.json.gz
+
+Add `<repo_owner>` to export a repository that does not belong to your Github user or from an organization your Github user can access.
+
+For example to export all issues from the repository `https://github.com/emersion/kanshi`, use:
+
+```
+go run . emersion kanshi | gzip >todo.json.gz
+```
Then import the tracker dump to SourceHut.
diff --git a/main.go b/main.go
index e341e20..278531e 100644
--- a/main.go
+++ b/main.go
@@ -12,32 +12,60 @@ import (
const upstream = "https://github.com"
-func populateLabels(client *githubv4.Client, repoName string, tracker *Tracker) {
- var query struct {
+type repo_labels struct {
+ Labels struct {
+ Nodes []GHLabel
+ TotalCount int64
+ } `graphql:"labels(first: 100)"`
+}
+
+type repo_issues struct {
+ Issues struct {
+ Nodes []GHIssue
+ PageInfo struct {
+ EndCursor githubv4.String
+ HasNextPage bool
+ }
+ TotalCount int64
+ } `graphql:"issues(first: 100, after: $issuesCursor)"`
+}
+
+func populateLabels(client *githubv4.Client, owner, repoName string, tracker *Tracker) {
+
+ var query_no_owner struct {
Viewer struct {
- Repository *struct {
- Labels struct {
- Nodes []GHLabel
- TotalCount int64
- } `graphql:"labels(first: 100)"`
- } `graphql:"repository(name: $name)"`
+ Repository repo_labels `graphql:"repository(name: $name)"`
}
}
+ var query_with_owner struct {
+ Repository repo_labels `graphql:"repository(owner: $owner, name: $name)"`
+ }
+
variables := map[string]interface{}{
"name": githubv4.String(repoName),
}
+ if owner != "" {
+ variables["owner"] = githubv4.String(owner)
+ }
log.Print("Fetching labels...")
- if err := client.Query(context.Background(), &query, variables); err != nil {
- log.Fatal(err)
+ var repo = repo_labels{}
+ if owner == "" {
+ if err := client.Query(context.Background(), &query_no_owner, variables); err != nil {
+ log.Fatal(err)
+ }
+ repo = query_no_owner.Viewer.Repository
+ } else {
+ if err := client.Query(context.Background(), &query_with_owner, variables); err != nil {
+ log.Fatal(err)
+ }
+ repo = query_with_owner.Repository
}
- repo := query.Viewer.Repository
if repo == nil {
log.Fatalf("Repository %q not found", repoName)
}
-
if repo.Labels.TotalCount > 100 {
log.Fatalf("Too many labels (%v)", repo.Labels.TotalCount)
}
@@ -47,22 +75,18 @@ func populateLabels(client *githubv4.Client, repoName string, tracker *Tracker)
}
}
-func populateTickets(client *githubv4.Client, repoName string, tracker *Tracker) {
- var query struct {
+func populateTickets(client *githubv4.Client, owner, repoName string, tracker *Tracker) {
+
+ var query_no_owner struct {
Viewer struct {
- Repository struct {
- Issues struct {
- Nodes []GHIssue
- PageInfo struct {
- EndCursor githubv4.String
- HasNextPage bool
- }
- TotalCount int64
- } `graphql:"issues(first: 100, after: $issuesCursor)"`
- } `graphql:"repository(name: $name)"`
+ Repository repo_issues `graphql:"repository(name: $name)"`
}
}
+ var query_with_owner struct {
+ Repository repo_issues `graphql:"repository(owner:$owner,name: $name)"`
+ }
+
variables := map[string]interface{}{
"name": githubv4.String(repoName),
"issuesCursor": (*githubv4.String)(nil),
@@ -70,7 +94,11 @@ func populateTickets(client *githubv4.Client, repoName string, tracker *Tracker)
githubv4.IssueTimelineItemsItemTypeIssueComment,
},
}
+ if owner != "" {
+ variables["owner"] = githubv4.String(owner)
+ }
+ var repo = repo_issues{}
total := int64(0)
for {
pct := 0
@@ -79,31 +107,50 @@ func populateTickets(client *githubv4.Client, repoName string, tracker *Tracker)
}
log.Printf("Fetching issues (%v%% completed)...", pct)
- if err := client.Query(context.Background(), &query, variables); err != nil {
- log.Fatal(err)
+ if owner == "" {
+ if err := client.Query(context.Background(), &query_no_owner, variables); err != nil {
+ log.Fatal(err)
+ }
+ repo = query_no_owner.Viewer.Repository
+ } else {
+ if err := client.Query(context.Background(), &query_with_owner, variables); err != nil {
+ log.Fatal(err)
+ }
+ repo = query_with_owner.Repository
}
- issues := query.Viewer.Repository.Issues
-
- total = issues.TotalCount
+ total = repo.Issues.TotalCount
- for _, issue := range issues.Nodes {
+ for _, issue := range repo.Issues.Nodes {
tracker.Tickets = append(tracker.Tickets, *issue.ToSrHt())
}
- if !issues.PageInfo.HasNextPage {
+ if !repo.Issues.PageInfo.HasNextPage {
break
}
- variables["issuesCursor"] = githubv4.NewString(issues.PageInfo.EndCursor)
+ variables["issuesCursor"] = githubv4.NewString(repo.Issues.PageInfo.EndCursor)
}
}
func main() {
- if len(os.Args) < 1 {
- log.Fatal("usage: gh2srht <repo>")
+ if len(os.Args) < 2 || len(os.Args) > 3 {
+ log.Println("usage: gh2srht <user-or-org> <repo>")
+ log.Println("or: gh2srht <repo>")
+ log.Println("")
+ log.Println("examples: gh2srht emersion kanshi")
+ log.Println(" gh2srht kanshi")
+ os.Exit(1)
+ }
+
+ owner, repoName := "", ""
+ if len(os.Args) == 2 {
+ repoName = os.Args[1]
+ }
+ if len(os.Args) == 3 {
+ owner = os.Args[1]
+ repoName = os.Args[2]
}
- repoName := os.Args[1]
token := os.Getenv("GITHUB_TOKEN")
if token == "" {
@@ -125,8 +172,8 @@ func main() {
Tickets: make([]Ticket, 0),
}
- populateLabels(client, repoName, &tracker)
- populateTickets(client, repoName, &tracker)
+ populateLabels(client, owner, repoName, &tracker)
+ populateTickets(client, owner, repoName, &tracker)
log.Print("Writing tracker dump...")
--
2.35.1