2020-12-27 03:34:19 +00:00
|
|
|
// Copyright 2020 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"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
|
|
|
|
2021-11-16 15:25:33 +00:00
|
|
|
base "code.gitea.io/gitea/modules/migration"
|
2020-12-27 03:34:19 +00:00
|
|
|
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
// RepositoryRestorer implements an Downloader from the local directory
|
|
|
|
type RepositoryRestorer struct {
|
2021-01-21 19:33:58 +00:00
|
|
|
base.NullDownloader
|
2022-01-26 09:45:51 +00:00
|
|
|
ctx context.Context
|
|
|
|
baseDir string
|
|
|
|
repoOwner string
|
|
|
|
repoName string
|
|
|
|
validation bool
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewRepositoryRestorer creates a repository restorer which could restore repository from a dumped folder
|
2022-01-26 09:45:51 +00:00
|
|
|
func NewRepositoryRestorer(ctx context.Context, baseDir, owner, repoName string, validation bool) (*RepositoryRestorer, error) {
|
2020-12-27 03:34:19 +00:00
|
|
|
baseDir, err := filepath.Abs(baseDir)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &RepositoryRestorer{
|
2022-01-26 09:45:51 +00:00
|
|
|
ctx: ctx,
|
|
|
|
baseDir: baseDir,
|
|
|
|
repoOwner: owner,
|
|
|
|
repoName: repoName,
|
|
|
|
validation: validation,
|
2020-12-27 03:34:19 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RepositoryRestorer) commentDir() string {
|
|
|
|
return filepath.Join(r.baseDir, "comments")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RepositoryRestorer) reviewDir() string {
|
|
|
|
return filepath.Join(r.baseDir, "reviews")
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetContext set context
|
|
|
|
func (r *RepositoryRestorer) SetContext(ctx context.Context) {
|
|
|
|
r.ctx = ctx
|
|
|
|
}
|
|
|
|
|
2021-02-22 03:57:41 +00:00
|
|
|
func (r *RepositoryRestorer) getRepoOptions() (map[string]string, error) {
|
2020-12-27 03:34:19 +00:00
|
|
|
p := filepath.Join(r.baseDir, "repo.yml")
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-20 17:46:10 +00:00
|
|
|
opts := make(map[string]string)
|
2020-12-27 03:34:19 +00:00
|
|
|
err = yaml.Unmarshal(bs, &opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-22 03:57:41 +00:00
|
|
|
return opts, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRepoInfo returns a repository information
|
|
|
|
func (r *RepositoryRestorer) GetRepoInfo() (*base.Repository, error) {
|
|
|
|
opts, err := r.getRepoOptions()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-12-27 03:34:19 +00:00
|
|
|
|
|
|
|
isPrivate, _ := strconv.ParseBool(opts["is_private"])
|
|
|
|
|
|
|
|
return &base.Repository{
|
|
|
|
Owner: r.repoOwner,
|
|
|
|
Name: r.repoName,
|
|
|
|
IsPrivate: isPrivate,
|
|
|
|
Description: opts["description"],
|
|
|
|
OriginalURL: opts["original_url"],
|
2021-06-04 13:14:20 +00:00
|
|
|
CloneURL: filepath.Join(r.baseDir, "git"),
|
2020-12-27 03:34:19 +00:00
|
|
|
DefaultBranch: opts["default_branch"],
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTopics return github topics
|
|
|
|
func (r *RepositoryRestorer) GetTopics() ([]string, error) {
|
|
|
|
p := filepath.Join(r.baseDir, "topic.yml")
|
|
|
|
|
2022-01-20 17:46:10 +00:00
|
|
|
topics := struct {
|
2020-12-27 03:34:19 +00:00
|
|
|
Topics []string `yaml:"topics"`
|
|
|
|
}{}
|
|
|
|
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
2022-01-25 02:44:12 +00:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2020-12-27 03:34:19 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(bs, &topics)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return topics.Topics, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetMilestones returns milestones
|
|
|
|
func (r *RepositoryRestorer) GetMilestones() ([]*base.Milestone, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
milestones := make([]*base.Milestone, 0, 10)
|
2020-12-27 03:34:19 +00:00
|
|
|
p := filepath.Join(r.baseDir, "milestone.yml")
|
2022-01-26 09:45:51 +00:00
|
|
|
err := base.Load(p, &milestones, r.validation)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return milestones, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetReleases returns releases
|
|
|
|
func (r *RepositoryRestorer) GetReleases() ([]*base.Release, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
releases := make([]*base.Release, 0, 10)
|
2020-12-27 03:34:19 +00:00
|
|
|
p := filepath.Join(r.baseDir, "release.yml")
|
|
|
|
_, err := os.Stat(p)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(bs, &releases)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, rel := range releases {
|
|
|
|
for _, asset := range rel.Assets {
|
2021-06-04 13:14:20 +00:00
|
|
|
if asset.DownloadURL != nil {
|
|
|
|
*asset.DownloadURL = "file://" + filepath.Join(r.baseDir, *asset.DownloadURL)
|
|
|
|
}
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return releases, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLabels returns labels
|
|
|
|
func (r *RepositoryRestorer) GetLabels() ([]*base.Label, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
labels := make([]*base.Label, 0, 10)
|
2020-12-27 03:34:19 +00:00
|
|
|
p := filepath.Join(r.baseDir, "label.yml")
|
|
|
|
_, err := os.Stat(p)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(bs, &labels)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return labels, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetIssues returns issues according start and limit
|
|
|
|
func (r *RepositoryRestorer) GetIssues(page, perPage int) ([]*base.Issue, bool, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
issues := make([]*base.Issue, 0, 10)
|
2020-12-27 03:34:19 +00:00
|
|
|
p := filepath.Join(r.baseDir, "issue.yml")
|
2022-01-26 09:45:51 +00:00
|
|
|
err := base.Load(p, &issues, r.validation)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, true, nil
|
|
|
|
}
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
2021-08-21 22:47:45 +00:00
|
|
|
for _, issue := range issues {
|
|
|
|
issue.Context = base.BasicIssueContext(issue.Number)
|
|
|
|
}
|
2020-12-27 03:34:19 +00:00
|
|
|
return issues, true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetComments returns comments according issueNumber
|
2021-06-30 07:23:49 +00:00
|
|
|
func (r *RepositoryRestorer) GetComments(opts base.GetCommentOptions) ([]*base.Comment, bool, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
comments := make([]*base.Comment, 0, 10)
|
2021-08-21 22:47:45 +00:00
|
|
|
p := filepath.Join(r.commentDir(), fmt.Sprintf("%d.yml", opts.Context.ForeignID()))
|
2020-12-27 03:34:19 +00:00
|
|
|
_, err := os.Stat(p)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
2021-06-30 07:23:49 +00:00
|
|
|
return nil, false, nil
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
2021-06-30 07:23:49 +00:00
|
|
|
return nil, false, err
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
|
|
|
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
2021-06-30 07:23:49 +00:00
|
|
|
return nil, false, err
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(bs, &comments)
|
|
|
|
if err != nil {
|
2021-06-30 07:23:49 +00:00
|
|
|
return nil, false, err
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
2021-06-30 07:23:49 +00:00
|
|
|
return comments, false, nil
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPullRequests returns pull requests according page and perPage
|
|
|
|
func (r *RepositoryRestorer) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
pulls := make([]*base.PullRequest, 0, 10)
|
2020-12-27 03:34:19 +00:00
|
|
|
p := filepath.Join(r.baseDir, "pull_request.yml")
|
|
|
|
_, err := os.Stat(p)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, true, nil
|
|
|
|
}
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(bs, &pulls)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
for _, pr := range pulls {
|
|
|
|
pr.PatchURL = "file://" + filepath.Join(r.baseDir, pr.PatchURL)
|
2021-08-21 22:47:45 +00:00
|
|
|
pr.Context = base.BasicIssueContext(pr.Number)
|
2020-12-27 03:34:19 +00:00
|
|
|
}
|
|
|
|
return pulls, true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetReviews returns pull requests review
|
2021-08-21 22:47:45 +00:00
|
|
|
func (r *RepositoryRestorer) GetReviews(context base.IssueContext) ([]*base.Review, error) {
|
2022-01-20 17:46:10 +00:00
|
|
|
reviews := make([]*base.Review, 0, 10)
|
2021-08-21 22:47:45 +00:00
|
|
|
p := filepath.Join(r.reviewDir(), fmt.Sprintf("%d.yml", context.ForeignID()))
|
2020-12-27 03:34:19 +00:00
|
|
|
_, err := os.Stat(p)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-22 05:38:34 +00:00
|
|
|
bs, err := os.ReadFile(p)
|
2020-12-27 03:34:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(bs, &reviews)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return reviews, nil
|
|
|
|
}
|