A tool to migrate GitHub Repositories to Gitea including all issues
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

123 lines
3.3 KiB

  1. package cmd
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "code.gitea.io/sdk/gitea"
  7. "git.jonasfranz.software/JonasFranzDEV/gitea-github-migrator/migrations"
  8. "github.com/google/go-github/github"
  9. "github.com/urfave/cli"
  10. "golang.org/x/oauth2"
  11. )
  12. // CmdMigrate migrates a given repository to gitea
  13. var CmdMigrate = cli.Command{
  14. Name: "migrate",
  15. Usage: "migrates a github to a gitea repository",
  16. Action: runMigrate,
  17. Flags: append(defaultMigrateFlags,
  18. cli.StringFlag{
  19. Name: "gh-repo",
  20. Usage: "GitHub Repository",
  21. Value: "username/reponame",
  22. EnvVar: "GH_REPOSITORY",
  23. },
  24. ),
  25. }
  26. func runMigrate(ctx *cli.Context) error {
  27. m := &migrations.Migratory{
  28. Client: gitea.NewClient(ctx.String("url"), ctx.String("token")),
  29. Private: ctx.Bool("private"),
  30. NewOwnerID: ctx.Int64("owner"),
  31. }
  32. if m.NewOwnerID == 0 {
  33. usr, err := m.Client.GetMyUserInfo()
  34. if err != nil {
  35. return fmt.Errorf("cannot fetch user info about current user: %v", err)
  36. }
  37. m.NewOwnerID = usr.ID
  38. }
  39. c := context.Background()
  40. var gc *github.Client
  41. if ctx.IsSet("gh-token") {
  42. ts := oauth2.StaticTokenSource(
  43. &oauth2.Token{AccessToken: ctx.String("gh-token")},
  44. )
  45. tc := oauth2.NewClient(c, ts)
  46. gc = github.NewClient(tc)
  47. } else {
  48. gc = github.NewClient(nil)
  49. }
  50. username := strings.Split(ctx.String("gh-repo"), "/")[0]
  51. repo := strings.Split(ctx.String("gh-repo"), "/")[1]
  52. return migrate(c, gc, m, username, repo, ctx.Bool("only-repo"))
  53. }
  54. func migrate(c context.Context, gc *github.Client, m *migrations.Migratory, username, repo string, onlyRepo bool) error {
  55. fmt.Printf("Fetching repository %s/%s...\n", username, repo)
  56. gr, _, err := gc.Repositories.Get(c, username, repo)
  57. if err != nil {
  58. return fmt.Errorf("error while fetching repo[%s/%s]: %v", username, repo, err)
  59. }
  60. fmt.Printf("Migrating repository %s/%s...\n", username, repo)
  61. var mr *gitea.Repository
  62. if mr, err = m.Repository(gr); err != nil {
  63. return fmt.Errorf("error while migrating repo[%s/%s]: %v", username, repo, err)
  64. }
  65. fmt.Printf("Repository migrated to %s/%s\n", mr.Owner.UserName, mr.Name)
  66. if onlyRepo {
  67. return nil
  68. }
  69. fmt.Println("Fetching issues...")
  70. opt := &github.IssueListByRepoOptions{
  71. Sort: "created",
  72. Direction: "asc",
  73. State: "all",
  74. ListOptions: github.ListOptions{
  75. PerPage: 100,
  76. },
  77. }
  78. var allIssues = make([]*github.Issue, 0)
  79. for {
  80. issues, resp, err := gc.Issues.ListByRepo(c, username, repo, opt)
  81. if err != nil {
  82. return fmt.Errorf("error while listing repos: %v", err)
  83. }
  84. allIssues = append(allIssues, issues...)
  85. if resp.NextPage == 0 {
  86. break
  87. }
  88. opt.Page = resp.NextPage
  89. }
  90. fmt.Println("Migrating issues...")
  91. for _, gi := range allIssues {
  92. fmt.Printf("Migrating #%d...\n", *gi.Number)
  93. issue, err := m.Issue(gi)
  94. if err != nil {
  95. return fmt.Errorf("migrating issue[id: %d]: %v", *gi.ID, err)
  96. }
  97. comments, _, err := gc.Issues.ListComments(c, username, repo, gi.GetNumber(), nil)
  98. if err != nil {
  99. return fmt.Errorf("fetching issue[id: %d] comments: %v", *gi.ID, err)
  100. }
  101. for _, gc := range comments {
  102. fmt.Printf("-> %d...", gc.ID)
  103. if _, err := m.IssueComment(issue, gc); err != nil {
  104. return fmt.Errorf("migrating issue comment [issue: %d, comment: %d]: %v", *gi.ID, gc.ID, err)
  105. }
  106. fmt.Print("Done!\n")
  107. }
  108. fmt.Printf("Migrated #%d...\n", *gi.Number)
  109. }
  110. return nil
  111. }