Skip to content

Commit

Permalink
Add migration from GitBucket (go-gitea#16767)
Browse files Browse the repository at this point in the history
This PR adds [GitBucket](https://gitbucket.github.io/) as migration source.

Supported:
- Milestones
- Issues
- Pull Requests
- Comments
- Reviews
- Labels

There is no public usable instance so no integration tests added.
  • Loading branch information
KN4CK3R authored and Stelios Malathouras committed Mar 28, 2022
1 parent f233f84 commit 63147a2
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 106 deletions.
2 changes: 2 additions & 0 deletions modules/convert/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ func ToGitServiceType(value string) structs.GitServiceType {
return structs.GogsService
case "onedev":
return structs.OneDevService
case "gitbucket":
return structs.GitBucketService
default:
return structs.PlainGitService
}
Expand Down
72 changes: 72 additions & 0 deletions modules/migrations/gitbucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package migrations

import (
"context"
"net/url"
"strings"

"code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/structs"
)

var (
_ base.Downloader = &GitBucketDownloader{}
_ base.DownloaderFactory = &GitBucketDownloaderFactory{}
)

func init() {
RegisterDownloaderFactory(&GitBucketDownloaderFactory{})
}

// GitBucketDownloaderFactory defines a GitBucket downloader factory
type GitBucketDownloaderFactory struct {
}

// New returns a Downloader related to this factory according MigrateOptions
func (f *GitBucketDownloaderFactory) New(ctx context.Context, opts base.MigrateOptions) (base.Downloader, error) {
u, err := url.Parse(opts.CloneAddr)
if err != nil {
return nil, err
}

baseURL := u.Scheme + "://" + u.Host
fields := strings.Split(u.Path, "/")
oldOwner := fields[1]
oldName := strings.TrimSuffix(fields[2], ".git")

return NewGitBucketDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil
}

// GitServiceType returns the type of git service
func (f *GitBucketDownloaderFactory) GitServiceType() structs.GitServiceType {
return structs.GitBucketService
}

// GitBucketDownloader implements a Downloader interface to get repository information
// from GitBucket via GithubDownloader
type GitBucketDownloader struct {
*GithubDownloaderV3
}

// NewGitBucketDownloader creates a GitBucket downloader
func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader {
githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName)
githubDownloader.SkipReactions = true
return &GitBucketDownloader{
githubDownloader,
}
}

// SupportGetRepoComments return true if it supports get repo comments
func (g *GitBucketDownloader) SupportGetRepoComments() bool {
return false
}

// GetReviews is not supported
func (g *GitBucketDownloader) GetReviews(context base.IssueContext) ([]*base.Review, error) {
return nil, &base.ErrNotSupported{Entity: "Reviews"}
}
209 changes: 110 additions & 99 deletions modules/migrations/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@ func (f *GithubDownloaderV3Factory) GitServiceType() structs.GitServiceType {
// from github via APIv3
type GithubDownloaderV3 struct {
base.NullDownloader
ctx context.Context
clients []*github.Client
repoOwner string
repoName string
userName string
password string
rates []*github.Rate
curClientIdx int
maxPerPage int
ctx context.Context
clients []*github.Client
repoOwner string
repoName string
userName string
password string
rates []*github.Rate
curClientIdx int
maxPerPage int
SkipReactions bool
}

// NewGithubDownloaderV3 creates a github Downloader via github v3 API
Expand Down Expand Up @@ -428,25 +429,27 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool,

// get reactions
var reactions []*base.Reaction
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, issue.GetNumber(), &github.ListOptions{
Page: i,
PerPage: perPage,
})
if err != nil {
return nil, false, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
if !g.SkipReactions {
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, issue.GetNumber(), &github.ListOptions{
Page: i,
PerPage: perPage,
})
if err != nil {
return nil, false, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
})
}
}
}

Expand Down Expand Up @@ -516,25 +519,27 @@ func (g *GithubDownloaderV3) getComments(issueContext base.IssueContext) ([]*bas
for _, comment := range comments {
// get reactions
var reactions []*base.Reaction
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{
Page: i,
PerPage: g.maxPerPage,
})
if err != nil {
return nil, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
if !g.SkipReactions {
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{
Page: i,
PerPage: g.maxPerPage,
})
if err != nil {
return nil, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
})
}
}
}

Expand Down Expand Up @@ -588,25 +593,27 @@ func (g *GithubDownloaderV3) GetAllComments(page, perPage int) ([]*base.Comment,
for _, comment := range comments {
// get reactions
var reactions []*base.Reaction
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{
Page: i,
PerPage: g.maxPerPage,
})
if err != nil {
return nil, false, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
if !g.SkipReactions {
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{
Page: i,
PerPage: g.maxPerPage,
})
if err != nil {
return nil, false, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
})
}
}
}
idx := strings.LastIndex(*comment.IssueURL, "/")
Expand Down Expand Up @@ -656,25 +663,27 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq

// get reactions
var reactions []*base.Reaction
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, pr.GetNumber(), &github.ListOptions{
Page: i,
PerPage: perPage,
})
if err != nil {
return nil, false, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
if !g.SkipReactions {
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, pr.GetNumber(), &github.ListOptions{
Page: i,
PerPage: perPage,
})
if err != nil {
return nil, false, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
})
}
}
}

Expand Down Expand Up @@ -737,25 +746,27 @@ func (g *GithubDownloaderV3) convertGithubReviewComments(cs []*github.PullReques
for _, c := range cs {
// get reactions
var reactions []*base.Reaction
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListPullRequestCommentReactions(g.ctx, g.repoOwner, g.repoName, c.GetID(), &github.ListOptions{
Page: i,
PerPage: g.maxPerPage,
})
if err != nil {
return nil, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
if !g.SkipReactions {
for i := 1; ; i++ {
g.waitAndPickClient()
res, resp, err := g.getClient().Reactions.ListPullRequestCommentReactions(g.ctx, g.repoOwner, g.repoName, c.GetID(), &github.ListOptions{
Page: i,
PerPage: g.maxPerPage,
})
if err != nil {
return nil, err
}
g.setRate(&resp.Rate)
if len(res) == 0 {
break
}
for _, reaction := range res {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.GetID(),
UserName: reaction.User.GetLogin(),
Content: reaction.GetContent(),
})
}
}
}

Expand Down
18 changes: 11 additions & 7 deletions modules/structs/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,14 @@ type GitServiceType int

// enumerate all GitServiceType
const (
NotMigrated GitServiceType = iota // 0 not migrated from external sites
PlainGitService // 1 plain git service
GithubService // 2 github.com
GiteaService // 3 gitea service
GitlabService // 4 gitlab service
GogsService // 5 gogs service
OneDevService // 6 onedev service
NotMigrated GitServiceType = iota // 0 not migrated from external sites
PlainGitService // 1 plain git service
GithubService // 2 github.com
GiteaService // 3 gitea service
GitlabService // 4 gitlab service
GogsService // 5 gogs service
OneDevService // 6 onedev service
GitBucketService // 7 gitbucket service
)

// Name represents the service type's name
Expand All @@ -270,6 +271,8 @@ func (gt GitServiceType) Title() string {
return "Gogs"
case OneDevService:
return "OneDev"
case GitBucketService:
return "GitBucket"
case PlainGitService:
return "Git"
}
Expand Down Expand Up @@ -326,5 +329,6 @@ var (
GiteaService,
GogsService,
OneDevService,
GitBucketService,
}
)
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ migrate.gitlab.description = Migrate data from gitlab.com or other GitLab instan
migrate.gitea.description = Migrate data from gitea.com or other Gitea instances.
migrate.gogs.description = Migrate data from notabug.org or other Gogs instances.
migrate.onedev.description = Migrate data from code.onedev.io or other OneDev instances.
migrate.gitbucket.description = Migrating data from GitBucket instances.
migrate.migrating_git = Migrating Git Data
migrate.migrating_topics = Migrating Topics
migrate.migrating_milestones = Migrating Milestones
Expand Down
1 change: 1 addition & 0 deletions public/img/svg/gitea-gitbucket.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 63147a2

Please sign in to comment.