|
| 1 | +// Copyright 2019 The Gitea Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a MIT-style |
| 3 | +// license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +package migrations |
| 6 | + |
| 7 | +import ( |
| 8 | + "fmt" |
| 9 | + "net/http" |
| 10 | + "net/url" |
| 11 | + "strings" |
| 12 | + "time" |
| 13 | + |
| 14 | + "code.gitea.io/gitea/modules/log" |
| 15 | + "code.gitea.io/gitea/modules/migrations/base" |
| 16 | + "code.gitea.io/gitea/modules/structs" |
| 17 | + |
| 18 | + "github.com/gogs/go-gogs-client" |
| 19 | +) |
| 20 | + |
| 21 | +var ( |
| 22 | + _ base.Downloader = &GogsDownloader{} |
| 23 | + _ base.DownloaderFactory = &GogsDownloaderFactory{} |
| 24 | +) |
| 25 | + |
| 26 | +func init() { |
| 27 | + RegisterDownloaderFactory(&GogsDownloaderFactory{}) |
| 28 | +} |
| 29 | + |
| 30 | +// GogsDownloaderFactory defines a gogs downloader factory |
| 31 | +type GogsDownloaderFactory struct { |
| 32 | +} |
| 33 | + |
| 34 | +// Match returns ture if the migration remote URL matched this downloader factory |
| 35 | +func (f *GogsDownloaderFactory) Match(opts base.MigrateOptions) (bool, error) { |
| 36 | + if opts.GitServiceType == structs.GogsService { |
| 37 | + return true, nil |
| 38 | + } |
| 39 | + return false, nil |
| 40 | +} |
| 41 | + |
| 42 | +// New returns a Downloader related to this factory according MigrateOptions |
| 43 | +func (f *GogsDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader, error) { |
| 44 | + u, err := url.Parse(opts.CloneAddr) |
| 45 | + if err != nil { |
| 46 | + return nil, err |
| 47 | + } |
| 48 | + |
| 49 | + baseURL := u.Scheme + "://" + u.Host |
| 50 | + fields := strings.Split(u.Path, "/") |
| 51 | + oldOwner := fields[1] |
| 52 | + oldName := strings.TrimSuffix(fields[2], ".git") |
| 53 | + |
| 54 | + log.Trace("Create gogs downloader: %s/%s", oldOwner, oldName) |
| 55 | + |
| 56 | + return NewGogsDownloader(baseURL, opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil |
| 57 | +} |
| 58 | + |
| 59 | +// GitServiceType returns the type of git service |
| 60 | +func (f *GogsDownloaderFactory) GitServiceType() structs.GitServiceType { |
| 61 | + return structs.GogsService |
| 62 | +} |
| 63 | + |
| 64 | +// GogsDownloader implements a Downloader interface to get repository informations |
| 65 | +// from gogs via API |
| 66 | +type GogsDownloader struct { |
| 67 | + client *gogs.Client |
| 68 | + baseURL string |
| 69 | + repoOwner string |
| 70 | + repoName string |
| 71 | + userName string |
| 72 | + password string |
| 73 | +} |
| 74 | + |
| 75 | +// NewGogsDownloader creates a gogs Downloader via gogs API |
| 76 | +func NewGogsDownloader(baseURL, userName, password, repoOwner, repoName string) *GogsDownloader { |
| 77 | + var downloader = GogsDownloader{ |
| 78 | + baseURL: baseURL, |
| 79 | + userName: userName, |
| 80 | + password: password, |
| 81 | + repoOwner: repoOwner, |
| 82 | + repoName: repoName, |
| 83 | + } |
| 84 | + |
| 85 | + var client *gogs.Client |
| 86 | + if userName != "" { |
| 87 | + if password == "" { |
| 88 | + client = gogs.NewClient(baseURL, userName) |
| 89 | + } else { |
| 90 | + client = gogs.NewClient(baseURL, "") |
| 91 | + client.SetHTTPClient(&http.Client{ |
| 92 | + Transport: &http.Transport{ |
| 93 | + Proxy: func(req *http.Request) (*url.URL, error) { |
| 94 | + req.SetBasicAuth(userName, password) |
| 95 | + return nil, nil |
| 96 | + }, |
| 97 | + }, |
| 98 | + }) |
| 99 | + } |
| 100 | + } |
| 101 | + downloader.client = client |
| 102 | + return &downloader |
| 103 | +} |
| 104 | + |
| 105 | +// GetRepoInfo returns a repository information |
| 106 | +func (g *GogsDownloader) GetRepoInfo() (*base.Repository, error) { |
| 107 | + gr, err := g.client.GetRepo(g.repoOwner, g.repoName) |
| 108 | + if err != nil { |
| 109 | + return nil, err |
| 110 | + } |
| 111 | + |
| 112 | + // convert github repo to stand Repo |
| 113 | + return &base.Repository{ |
| 114 | + Owner: g.repoOwner, |
| 115 | + Name: g.repoName, |
| 116 | + IsPrivate: gr.Private, |
| 117 | + Description: gr.Description, |
| 118 | + CloneURL: gr.CloneURL, |
| 119 | + }, nil |
| 120 | +} |
| 121 | + |
| 122 | +// GetTopics return github topics |
| 123 | +func (g *GogsDownloader) GetTopics() ([]string, error) { |
| 124 | + return []string{}, nil |
| 125 | +} |
| 126 | + |
| 127 | +// GetMilestones returns milestones |
| 128 | +func (g *GogsDownloader) GetMilestones() ([]*base.Milestone, error) { |
| 129 | + var perPage = 100 |
| 130 | + var milestones = make([]*base.Milestone, 0, perPage) |
| 131 | + |
| 132 | + ms, err := g.client.ListRepoMilestones(g.repoOwner, g.repoName) |
| 133 | + if err != nil { |
| 134 | + return nil, err |
| 135 | + } |
| 136 | + |
| 137 | + t := time.Now() |
| 138 | + |
| 139 | + for _, m := range ms { |
| 140 | + milestones = append(milestones, &base.Milestone{ |
| 141 | + Title: m.Title, |
| 142 | + Description: m.Description, |
| 143 | + Deadline: m.Deadline, |
| 144 | + State: string(m.State), |
| 145 | + Created: t, |
| 146 | + Updated: &t, |
| 147 | + Closed: m.Closed, |
| 148 | + }) |
| 149 | + } |
| 150 | + |
| 151 | + return milestones, nil |
| 152 | +} |
| 153 | + |
| 154 | +func convertGogsLabel(label *gogs.Label) *base.Label { |
| 155 | + return &base.Label{ |
| 156 | + Name: label.Name, |
| 157 | + Color: label.Color, |
| 158 | + } |
| 159 | +} |
| 160 | + |
| 161 | +// GetLabels returns labels |
| 162 | +func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { |
| 163 | + var perPage = 100 |
| 164 | + var labels = make([]*base.Label, 0, perPage) |
| 165 | + ls, err := g.client.ListRepoLabels(g.repoOwner, g.repoName) |
| 166 | + if err != nil { |
| 167 | + return nil, err |
| 168 | + } |
| 169 | + |
| 170 | + for _, label := range ls { |
| 171 | + labels = append(labels, convertGogsLabel(label)) |
| 172 | + } |
| 173 | + |
| 174 | + return labels, nil |
| 175 | +} |
| 176 | + |
| 177 | +// GetReleases returns releases |
| 178 | +// FIXME: gogs API haven't support get releases |
| 179 | +func (g *GogsDownloader) GetReleases() ([]*base.Release, error) { |
| 180 | + return nil, ErrNotSupported |
| 181 | +} |
| 182 | + |
| 183 | +// GetIssues returns issues according start and limit, perPage is not supported |
| 184 | +func (g *GogsDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { |
| 185 | + var allIssues = make([]*base.Issue, 0, perPage) |
| 186 | + |
| 187 | + issues, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gogs.ListIssueOption{ |
| 188 | + Page: page, |
| 189 | + }) |
| 190 | + if err != nil { |
| 191 | + return nil, false, fmt.Errorf("error while listing repos: %v", err) |
| 192 | + } |
| 193 | + for _, issue := range issues { |
| 194 | + if issue.PullRequest != nil { |
| 195 | + continue |
| 196 | + } |
| 197 | + |
| 198 | + var milestone string |
| 199 | + if issue.Milestone != nil { |
| 200 | + milestone = issue.Milestone.Title |
| 201 | + } |
| 202 | + var labels = make([]*base.Label, 0, len(issue.Labels)) |
| 203 | + for _, l := range issue.Labels { |
| 204 | + labels = append(labels, convertGogsLabel(l)) |
| 205 | + } |
| 206 | + |
| 207 | + var closed *time.Time |
| 208 | + if issue.State == gogs.STATE_CLOSED { |
| 209 | + // gogs client haven't provide closed, so we use updated instead |
| 210 | + closed = &issue.Updated |
| 211 | + } |
| 212 | + |
| 213 | + allIssues = append(allIssues, &base.Issue{ |
| 214 | + Title: issue.Title, |
| 215 | + Number: issue.Index, |
| 216 | + PosterName: issue.Poster.Login, |
| 217 | + PosterEmail: issue.Poster.Email, |
| 218 | + Content: issue.Body, |
| 219 | + Milestone: milestone, |
| 220 | + State: string(issue.State), |
| 221 | + Created: issue.Created, |
| 222 | + Labels: labels, |
| 223 | + Closed: closed, |
| 224 | + }) |
| 225 | + } |
| 226 | + |
| 227 | + return allIssues, len(issues) == 0, nil |
| 228 | +} |
| 229 | + |
| 230 | +// GetComments returns comments according issueNumber |
| 231 | +func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { |
| 232 | + var allComments = make([]*base.Comment, 0, 100) |
| 233 | + |
| 234 | + comments, err := g.client.ListIssueComments(g.repoOwner, g.repoName, issueNumber) |
| 235 | + if err != nil { |
| 236 | + return nil, fmt.Errorf("error while listing repos: %v", err) |
| 237 | + } |
| 238 | + for _, comment := range comments { |
| 239 | + allComments = append(allComments, &base.Comment{ |
| 240 | + PosterName: comment.Poster.Login, |
| 241 | + PosterEmail: comment.Poster.Email, |
| 242 | + Content: comment.Body, |
| 243 | + Created: comment.Created, |
| 244 | + Updated: comment.Updated, |
| 245 | + }) |
| 246 | + } |
| 247 | + |
| 248 | + return allComments, nil |
| 249 | +} |
| 250 | + |
| 251 | +// GetPullRequests returns pull requests according page and perPage |
| 252 | +func (g *GogsDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) { |
| 253 | + return nil, ErrNotSupported |
| 254 | +} |
0 commit comments