Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git migration UX improvements #12619

Merged
merged 10 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions modules/auth/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
type MigrateRepoForm struct {
// required: true
CloneAddr string `json:"clone_addr" binding:"Required"`
Service int `json:"service"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
// required: true
UID int64 `json:"uid" binding:"Required"`
// required: true
Expand Down
8 changes: 7 additions & 1 deletion modules/migrations/base/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ package base

import (
"context"
"io"
"time"

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

// AssetDownloader downloads an asset (attachment) for a release
type AssetDownloader interface {
GetAsset(tag string, id int64) (io.ReadCloser, error)
}

// Downloader downloads the site repo informations
type Downloader interface {
AssetDownloader
SetContext(context.Context)
GetRepoInfo() (*Repository, error)
GetTopics() ([]string, error)
Expand All @@ -28,7 +35,6 @@ type Downloader interface {

// DownloaderFactory defines an interface to match a downloader implementation and create a downloader
type DownloaderFactory interface {
Match(opts MigrateOptions) (bool, error)
New(opts MigrateOptions) (Downloader, error)
GitServiceType() structs.GitServiceType
}
Expand Down
2 changes: 1 addition & 1 deletion modules/migrations/base/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "time"

// ReleaseAsset represents a release asset
type ReleaseAsset struct {
URL string
ID int64
Name string
ContentType *string
Size *int
Expand Down
2 changes: 1 addition & 1 deletion modules/migrations/base/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Uploader interface {
CreateRepo(repo *Repository, opts MigrateOptions) error
CreateTopics(topic ...string) error
CreateMilestones(milestones ...*Milestone) error
CreateReleases(releases ...*Release) error
CreateReleases(downloader Downloader, releases ...*Release) error
SyncTags() error
CreateLabels(labels ...*Label) error
CreateIssues(issues ...*Issue) error
Expand Down
6 changes: 6 additions & 0 deletions modules/migrations/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package migrations

import (
"context"
"io"

"code.gitea.io/gitea/modules/migrations/base"
)
Expand Down Expand Up @@ -64,6 +65,11 @@ func (g *PlainGitDownloader) GetReleases() ([]*base.Release, error) {
return nil, ErrNotSupported
}

// GetAsset returns an asset
func (g *PlainGitDownloader) GetAsset(_ string, _ int64) (io.ReadCloser, error) {
return nil, ErrNotSupported
}

// GetIssues returns issues according page and perPage
func (g *PlainGitDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) {
return nil, false, ErrNotSupported
Expand Down
13 changes: 7 additions & 6 deletions modules/migrations/gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,15 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
}

var remoteAddr = repo.CloneURL
if len(opts.AuthUsername) > 0 {
if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 {
u, err := url.Parse(repo.CloneURL)
if err != nil {
return err
}
u.User = url.UserPassword(opts.AuthUsername, opts.AuthPassword)
if len(opts.AuthToken) > 0 {
u.User = url.UserPassword("oauth2", opts.AuthToken)
}
remoteAddr = u.String()
}

Expand Down Expand Up @@ -210,7 +213,7 @@ func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error {
}

// CreateReleases creates releases
func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
func (g *GiteaLocalUploader) CreateReleases(downloader base.Downloader, releases ...*base.Release) error {
var rels = make([]*models.Release, 0, len(releases))
for _, release := range releases {
var rel = models.Release{
Expand Down Expand Up @@ -269,13 +272,11 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {

// download attachment
err = func() error {
resp, err := http.Get(asset.URL)
rc, err := downloader.GetAsset(rel.TagName, asset.ID)
if err != nil {
return err
}
defer resp.Body.Close()

_, err = storage.Attachments.Save(attach.RelativePath(), resp.Body)
_, err = storage.Attachments.Save(attach.RelativePath(), rc)
return err
}()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion modules/migrations/gitea_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestGiteaUploadRepo(t *testing.T) {
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)

var (
downloader = NewGithubDownloaderV3("", "", "go-xorm", "builder")
downloader = NewGithubDownloaderV3("", "", "", "go-xorm", "builder")
repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05")
uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName)
)
Expand Down
63 changes: 31 additions & 32 deletions modules/migrations/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
package migrations

import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
Expand Down Expand Up @@ -37,16 +40,6 @@ func init() {
type GithubDownloaderV3Factory struct {
}

// Match returns ture if the migration remote URL matched this downloader factory
func (f *GithubDownloaderV3Factory) Match(opts base.MigrateOptions) (bool, error) {
u, err := url.Parse(opts.CloneAddr)
if err != nil {
return false, err
}

return strings.EqualFold(u.Host, "github.com") && opts.AuthUsername != "", nil
}

// New returns a Downloader related to this factory according MigrateOptions
func (f *GithubDownloaderV3Factory) New(opts base.MigrateOptions) (base.Downloader, error) {
u, err := url.Parse(opts.CloneAddr)
Expand All @@ -60,7 +53,7 @@ func (f *GithubDownloaderV3Factory) New(opts base.MigrateOptions) (base.Download

log.Trace("Create github downloader: %s/%s", oldOwner, oldName)

return NewGithubDownloaderV3(opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil
return NewGithubDownloaderV3(opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil
}

// GitServiceType returns the type of git service
Expand All @@ -81,7 +74,7 @@ type GithubDownloaderV3 struct {
}

// NewGithubDownloaderV3 creates a github Downloader via github v3 API
func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *GithubDownloaderV3 {
func NewGithubDownloaderV3(userName, password, token, repoOwner, repoName string) *GithubDownloaderV3 {
var downloader = GithubDownloaderV3{
userName: userName,
password: password,
Expand All @@ -90,23 +83,19 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith
repoName: repoName,
}

var client *http.Client
if userName != "" {
if password == "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: userName},
)
client = oauth2.NewClient(downloader.ctx, ts)
} else {
client = &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
req.SetBasicAuth(userName, password)
return nil, nil
},
},
}
}
client := &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
req.SetBasicAuth(userName, password)
return nil, nil
},
},
}
if token != "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
client = oauth2.NewClient(downloader.ctx, ts)
}
downloader.client = github.NewClient(client)
return &downloader
Expand Down Expand Up @@ -290,10 +279,8 @@ func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease)
}

for _, asset := range rel.Assets {
u, _ := url.Parse(*asset.BrowserDownloadURL)
u.User = url.UserPassword(g.userName, g.password)
r.Assets = append(r.Assets, base.ReleaseAsset{
URL: u.String(),
ID: *asset.ID,
Name: *asset.Name,
ContentType: asset.ContentType,
Size: asset.Size,
Expand Down Expand Up @@ -331,6 +318,18 @@ func (g *GithubDownloaderV3) GetReleases() ([]*base.Release, error) {
return releases, nil
}

// GetAsset returns an asset
func (g *GithubDownloaderV3) GetAsset(_ string, id int64) (io.ReadCloser, error) {
asset, redir, err := g.client.Repositories.DownloadReleaseAsset(g.ctx, g.repoOwner, g.repoName, id, http.DefaultClient)
if err != nil {
return nil, err
}
if asset == nil {
return ioutil.NopCloser(bytes.NewBufferString(redir)), nil
}
return asset, nil
}

// GetIssues returns issues according start and limit
func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, error) {
opt := &github.IssueListByRepoOptions{
Expand Down
2 changes: 1 addition & 1 deletion modules/migrations/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func assertLabelEqual(t *testing.T, name, color, description string, label *base

func TestGitHubDownloadRepo(t *testing.T) {
GithubLimitRateRemaining = 3 //Wait at 3 remaining since we could have 3 CI in //
downloader := NewGithubDownloaderV3(os.Getenv("GITHUB_READ_TOKEN"), "", "go-gitea", "test_repo")
downloader := NewGithubDownloaderV3("", "", os.Getenv("GITHUB_READ_TOKEN"), "go-gitea", "test_repo")
err := downloader.RefreshRate()
assert.NoError(t, err)

Expand Down
57 changes: 30 additions & 27 deletions modules/migrations/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
Expand All @@ -32,21 +34,6 @@ func init() {
type GitlabDownloaderFactory struct {
}

// Match returns true if the migration remote URL matched this downloader factory
func (f *GitlabDownloaderFactory) Match(opts base.MigrateOptions) (bool, error) {
var matched bool

u, err := url.Parse(opts.CloneAddr)
if err != nil {
return false, err
}
if strings.EqualFold(u.Host, "gitlab.com") && opts.AuthUsername != "" {
matched = true
}

return matched, nil
}

// New returns a Downloader related to this factory according MigrateOptions
func (f *GitlabDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader, error) {
u, err := url.Parse(opts.CloneAddr)
Expand All @@ -56,10 +43,11 @@ func (f *GitlabDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader

baseURL := u.Scheme + "://" + u.Host
repoNameSpace := strings.TrimPrefix(u.Path, "/")
repoNameSpace = strings.TrimSuffix(repoNameSpace, ".git")

log.Trace("Create gitlab downloader. BaseURL: %s RepoName: %s", baseURL, repoNameSpace)

return NewGitlabDownloader(baseURL, repoNameSpace, opts.AuthUsername, opts.AuthPassword), nil
return NewGitlabDownloader(baseURL, repoNameSpace, opts.AuthUsername, opts.AuthPassword, opts.AuthToken), nil
}

// GitServiceType returns the type of git service
Expand All @@ -85,15 +73,13 @@ type GitlabDownloader struct {
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
// Use either a username/password, personal token entered into the username field, or anonymous/public access
// Note: Public access only allows very basic access
func NewGitlabDownloader(baseURL, repoPath, username, password string) *GitlabDownloader {
func NewGitlabDownloader(baseURL, repoPath, username, password, token string) *GitlabDownloader {
var gitlabClient *gitlab.Client
var err error
if username != "" {
if password == "" {
gitlabClient, err = gitlab.NewClient(username, gitlab.WithBaseURL(baseURL))
} else {
gitlabClient, err = gitlab.NewBasicAuthClient(username, password, gitlab.WithBaseURL(baseURL))
}
if token != "" {
gitlabClient, err = gitlab.NewClient(token, gitlab.WithBaseURL(baseURL))
} else {
gitlabClient, err = gitlab.NewBasicAuthClient(username, password, gitlab.WithBaseURL(baseURL))
}

if err != nil {
Expand Down Expand Up @@ -271,7 +257,7 @@ func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) {
}

func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Release {

var zero int
r := &base.Release{
TagName: rel.TagName,
TargetCommitish: rel.Commit.ID,
Expand All @@ -284,9 +270,11 @@ func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Relea

for k, asset := range rel.Assets.Links {
r.Assets = append(r.Assets, base.ReleaseAsset{
URL: asset.URL,
Name: asset.Name,
ContentType: &rel.Assets.Sources[k].Format,
ID: int64(asset.ID),
Name: asset.Name,
ContentType: &rel.Assets.Sources[k].Format,
Size: &zero,
DownloadCount: &zero,
})
}
return r
Expand Down Expand Up @@ -315,6 +303,21 @@ func (g *GitlabDownloader) GetReleases() ([]*base.Release, error) {
return releases, nil
}

// GetAsset returns an asset
func (g *GitlabDownloader) GetAsset(tag string, id int64) (io.ReadCloser, error) {
link, _, err := g.client.ReleaseLinks.GetReleaseLink(g.repoID, tag, int(id))
if err != nil {
return nil, err
}
resp, err := http.Get(link.URL)
if err != nil {
return nil, err
}

// resp.Body is closed by the uploader
return resp.Body, nil
}

// GetIssues returns issues according start and limit
// Note: issue label description and colors are not supported by the go-gitlab library at this time
// TODO: figure out how to transfer issue reactions
Expand Down
2 changes: 1 addition & 1 deletion modules/migrations/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestGitlabDownloadRepo(t *testing.T) {
t.Skipf("Can't access test repo, skipping %s", t.Name())
}

downloader := NewGitlabDownloader("https://gitlab.com", "gitea/test_repo", gitlabPersonalAccessToken, "")
downloader := NewGitlabDownloader("https://gitlab.com", "gitea/test_repo", "", "", gitlabPersonalAccessToken)
if downloader == nil {
t.Fatal("NewGitlabDownloader is nil")
}
Expand Down
Loading