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

Add support to import repository data from an exported data of Github #18165

Draft
wants to merge 72 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
87f508e
Add support to import repository data from an exported data of Github
lunny Jan 3, 2022
69ef887
Review comments
lunny Jan 3, 2022
9baecbf
add asset supports
lunny Jan 5, 2022
ca66095
Add more tests
lunny Jan 6, 2022
e026523
some improvements
lunny Jan 7, 2022
4fb0a78
fix dump
lunny Jan 7, 2022
b41f533
Add version check
lunny Jan 7, 2022
7d31829
more tests
lunny Jan 8, 2022
14a9677
Fix some bugs
lunny Jan 8, 2022
8ddde32
Fix bug
lunny Jan 8, 2022
6adb90f
improve get reviews
lunny Jan 10, 2022
3e7f20d
Fix lint
lunny Jan 10, 2022
acf3985
Fix review
lunny Jan 10, 2022
e5726ed
Improve some comments
lunny Jan 10, 2022
1c77daf
Fix label and milestone comments
lunny Jan 10, 2022
5d7577e
Fix close comment
lunny Jan 10, 2022
392f1f1
Fix bug
lunny Jan 12, 2022
712145f
Fix bugs when importing
lunny Jan 15, 2022
daca6ee
Fix bugs when importing
lunny Jan 15, 2022
e874444
Fix opened pull request
lunny Jan 16, 2022
d2bce40
Ignore reference comments
lunny Jan 16, 2022
0d6a1ea
improve pull view
lunny Jan 17, 2022
426effb
Fix bug
lunny Jan 18, 2022
81fe056
Fix bug
lunny Jan 20, 2022
ae8fe0c
add trace log
lunny Jan 21, 2022
0ca2dab
Improve some missed review
lunny Jan 22, 2022
95aa21c
Fix build
lunny Jan 22, 2022
f70f7d2
Fix lint
lunny Jan 22, 2022
1241095
Fix bug
lunny Jan 22, 2022
d52c8f1
Fix bug
lunny Jan 23, 2022
8ee93ed
Fix bug
lunny Jan 23, 2022
c201d75
Fix comment
lunny Jan 23, 2022
473ca7c
Some improvements
lunny Jan 25, 2022
4a7505e
rename getID to parseGitHubResID
lunny Jan 25, 2022
549230c
Some improvements
lunny Jan 26, 2022
1c99455
Use regex to replace commit hash and issue/pull
lunny Jan 26, 2022
8e7d9a3
upload assets and replace the links in issue/comment/pullrequest
lunny Feb 3, 2022
20f30f1
Fix lint
lunny Feb 3, 2022
cc964e7
fix upload attachment
lunny Feb 3, 2022
2e516b5
Fix lint
lunny Feb 3, 2022
cc2d527
Fix bug
lunny Feb 3, 2022
d76ff4f
Fix bug
lunny Feb 3, 2022
e806f19
Ignore unsupported event
lunny Feb 6, 2022
46d8251
Merge
lunny Mar 21, 2022
f10b3de
Fix lint
lunny Apr 7, 2022
eef99f6
Merge
lunny Apr 24, 2022
b78ad20
Revert changes on updateGitForPullRequest
lunny May 23, 2022
0ab78e9
Improve pr check
lunny May 24, 2022
d52fac0
Fix test
lunny May 24, 2022
98065f8
Fix test
lunny May 24, 2022
fd9fdf7
Merge main branch
lunny Jun 13, 2022
dbed616
Merge branch 'main' into lunny/import_github_export_data
lunny Jun 18, 2022
a15d33f
Fix lint
lunny Jun 18, 2022
8f37261
Merge branch 'main' into lunny/import_github_export_data
lunny Jun 18, 2022
6ef5aa4
Merge branch 'main' into lunny/import_github_export_data
lunny Jun 18, 2022
2f31ed5
Merge main branch
lunny Jul 4, 2022
44b3ee6
Merge branch 'main' into lunny/import_github_export_data
6543 Jul 4, 2022
171aa9b
Merge branch 'main' into lunny/import_github_export_data
6543 Jul 14, 2022
893085d
Merge branch 'main' into lunny/import_github_export_data
lunny Aug 11, 2022
1d45f83
Merge branch 'main' into lunny/import_github_export_data
lunny Aug 14, 2022
cb691fa
Merge branch 'lunny/import_github_export_data' of github.com:lunny/gi…
lunny Aug 14, 2022
7596f9b
Merge branch 'main' into lunny/import_github_export_data
lunny Aug 15, 2022
80f225e
Merge branch 'main' into lunny/import_github_export_data
6543 Aug 15, 2022
73e1a93
Merge main branch
lunny Oct 19, 2022
77b40c9
Merge branch 'lunny/import_github_export_data' of github.com:lunny/gi…
lunny Oct 19, 2022
5fc7a6e
Merge branch 'main' into lunny/import_github_export_data
6543 Oct 19, 2022
468fe45
Fix check
lunny Oct 20, 2022
8cbf15b
Merge branch 'main' into lunny/import_github_export_data
lunny Oct 20, 2022
6688205
Merge branch 'lunny/import_github_export_data' of github.com:lunny/gi…
lunny Oct 20, 2022
201aae0
Merge branch 'main' into lunny/import_github_export_data
wolfogre Feb 1, 2023
f2ed8b1
chore: lint codes
wolfogre Feb 1, 2023
61c6403
chore: revert intended rm
wolfogre Feb 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions cmd/restore_repo.go
Expand Up @@ -23,6 +23,15 @@ var CmdRestoreRepository = cli.Command{
Description: "This is a command for restoring the repository data.",
Action: runRestoreRepository,
Flags: []cli.Flag{
cli.StringFlag{
Name: "data_type, d",
Value: "gitea",
Usage: "The data type that will be imported, default is gitea, options are gitea, github",
},
cli.StringFlag{
Name: "repo_filepath, f",
Usage: "Repository compressed data path to restore from",
},
cli.StringFlag{
Name: "repo_dir, r",
Value: "./data",
Expand Down Expand Up @@ -62,6 +71,8 @@ func runRestoreRepository(c *cli.Context) error {
}
statusCode, errStr := private.RestoreRepo(
ctx,
c.String("data_type"),
c.String("repo_filepath"),
c.String("repo_dir"),
c.String("owner_name"),
c.String("repo_name"),
Expand Down
10 changes: 10 additions & 0 deletions models/issues/comment.go
Expand Up @@ -180,6 +180,16 @@ func (t CommentType) String() string {
return commentStrings[t]
}

// GetCommentTypeByString return the comment type by given comment type string
func GetCommentTypeByString(s string) CommentType {
for i, cs := range commentStrings {
if cs == s {
return CommentType(i)
}
}
return -1
}

// RoleDescriptor defines comment tag type
type RoleDescriptor int

Expand Down
16 changes: 14 additions & 2 deletions models/issues/label.go
Expand Up @@ -301,15 +301,15 @@ func DeleteLabel(id, labelID int64) error {
// GetLabelByID returns a label by given ID.
func GetLabelByID(ctx context.Context, labelID int64) (*Label, error) {
if labelID <= 0 {
return nil, ErrLabelNotExist{labelID}
return nil, ErrLabelNotExist{LabelID: labelID}
}

l := &Label{}
has, err := db.GetEngine(ctx).ID(labelID).Get(l)
if err != nil {
return nil, err
} else if !has {
return nil, ErrLabelNotExist{l.ID}
return nil, ErrLabelNotExist{LabelID: l.ID}
}
return l, nil
}
Expand Down Expand Up @@ -435,6 +435,18 @@ func CountLabelsByRepoID(repoID int64) (int64, error) {
return db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).Count(&Label{})
}

// GetLabelByRepoIDAndName get label from repo
func GetLabelByRepoIDAndName(repoID int64, name string) (*Label, error) {
var label Label
has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ? AND name = ?", repoID, name).Get(&label)
if err != nil {
return nil, err
} else if !has {
return nil, ErrLabelNotExist{}
}
return &label, nil
}

// ________
// \_____ \_______ ____
// / | \_ __ \/ ___\
Expand Down
20 changes: 20 additions & 0 deletions models/migrate.go
Expand Up @@ -91,6 +91,16 @@ func insertIssue(ctx context.Context, issue *issues_model.Issue) error {
}
}

for _, attach := range issue.Attachments {
attach.IssueID = issue.ID
}

if len(issue.Attachments) > 0 {
if _, err := sess.Insert(issue.Attachments); err != nil {
return err
}
}

return nil
}

Expand Down Expand Up @@ -124,6 +134,16 @@ func InsertIssueComments(comments []*issues_model.Comment) error {
return err
}
}

for _, attach := range comment.Attachments {
attach.IssueID = comment.IssueID
attach.CommentID = comment.ID
}
if len(comment.Attachments) > 0 {
if err := db.Insert(ctx, comment.Attachments); err != nil {
return err
}
}
}

for issueID := range issueIDs {
Expand Down
1 change: 1 addition & 0 deletions modules/git/diff.go
Expand Up @@ -52,6 +52,7 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
if err != nil {
return err
}

fileArgs := make([]string, 0)
if len(file) > 0 {
fileArgs = append(fileArgs, "--", file)
Expand Down
25 changes: 25 additions & 0 deletions modules/migration/asset.go
@@ -0,0 +1,25 @@
// Copyright 2022 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 migration

import (
"io"
"time"
)

// Asset represents an asset for issue, comment, release
type Asset struct {
ID int64
Name string
ContentType *string `yaml:"content_type"`
Size *int
DownloadCount *int `yaml:"download_count"`
Created time.Time
Updated time.Time
DownloadURL *string `yaml:"download_url"`
OriginalURL string
// if DownloadURL is nil, the function should be invoked
DownloadFunc func() (io.ReadCloser, error) `yaml:"-"`
}
41 changes: 40 additions & 1 deletion modules/migration/comment.go
Expand Up @@ -14,9 +14,47 @@ type Commentable interface {
GetContext() DownloaderContext
}

/*
"comment",
"reopen",
"close",
"issue_ref",
"commit_ref",
"comment_ref",
"pull_ref",
"label",
"milestone",
"assignees",
"change_title",
"delete_branch",
"start_tracking",
"stop_tracking",
"add_time_manual",
"cancel_tracking",
"added_deadline",
"modified_deadline",
"removed_deadline",
"add_dependency",
"remove_dependency",
"code",
"review",
"lock",
"unlock",
"change_target_branch",
"delete_time_manual",
"review_request",
"merge_pull",
"pull_push",
"project",
"project_board",
"dismiss_review",
"change_issue_ref",
*/

// Comment is a standard comment information
type Comment struct {
IssueIndex int64 `yaml:"issue_index"`
Type string // empty means comment
IssueIndex int64 `yaml:"issue_index"`
Index int64
PosterID int64 `yaml:"poster_id"`
PosterName string `yaml:"poster_name"`
Expand All @@ -25,6 +63,7 @@ type Comment struct {
Updated time.Time
Content string
Reactions []*Reaction
Assets []*Asset
}

// GetExternalName ExternalUserMigrated interface
Expand Down
20 changes: 18 additions & 2 deletions modules/migration/downloader.go
Expand Up @@ -11,6 +11,20 @@ import (
"code.gitea.io/gitea/modules/structs"
)

// GetCommentOptions represents an options for get comment
type GetCommentOptions struct {
Commentable
Page int
PageSize int
}

// GetReviewOptions represents an options for get reviews
type GetReviewOptions struct {
Reviewable
Page int
PageSize int
}

// Downloader downloads the site repo information
type Downloader interface {
SetContext(context.Context)
Expand All @@ -20,12 +34,14 @@ type Downloader interface {
GetReleases() ([]*Release, error)
GetLabels() ([]*Label, error)
GetIssues(page, perPage int) ([]*Issue, bool, error)
GetComments(commentable Commentable) ([]*Comment, bool, error)
GetComments(opts GetCommentOptions) ([]*Comment, bool, error)
GetAllComments(page, perPage int) ([]*Comment, bool, error)
SupportGetRepoComments() bool
GetPullRequests(page, perPage int) ([]*PullRequest, bool, error)
GetReviews(reviewable Reviewable) ([]*Review, error)
GetReviews(reviewable Reviewable) ([]*Review, bool, error)
SupportGetRepoReviews() bool
FormatCloneURL(opts MigrateOptions, remoteAddr string) (string, error)
CleanUp()
}

// DownloaderFactory defines an interface to match a downloader implementation and create a downloader
Expand Down
31 changes: 16 additions & 15 deletions modules/migration/issue.go
Expand Up @@ -9,21 +9,22 @@ import "time"

// Issue is a standard issue information
type Issue struct {
Number int64 `json:"number"`
PosterID int64 `yaml:"poster_id" json:"poster_id"`
PosterName string `yaml:"poster_name" json:"poster_name"`
PosterEmail string `yaml:"poster_email" json:"poster_email"`
Title string `json:"title"`
Content string `json:"content"`
Ref string `json:"ref"`
Milestone string `json:"milestone"`
State string `json:"state"` // closed, open
IsLocked bool `yaml:"is_locked" json:"is_locked"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Closed *time.Time `json:"closed"`
Labels []*Label `json:"labels"`
Reactions []*Reaction `json:"reactions"`
Number int64 `json:"number"`
PosterID int64 `yaml:"poster_id" json:"poster_id"`
PosterName string `yaml:"poster_name" json:"poster_name"`
PosterEmail string `yaml:"poster_email" json:"poster_email"`
Title string `json:"title"`
Content string `json:"content"`
Ref string `json:"ref"`
Milestone string `json:"milestone"`
State string `json:"state"` // closed, open
IsLocked bool `yaml:"is_locked" json:"is_locked"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Closed *time.Time `json:"closed"`
Labels []*Label `json:"labels"`
Reactions []*Reaction `json:"reactions"`
Assets []*Asset
Assignees []string `json:"assignees"`
ForeignIndex int64 `json:"foreign_id"`
Context DownloaderContext `yaml:"-"`
Expand Down
15 changes: 12 additions & 3 deletions modules/migration/null_downloader.go
Expand Up @@ -48,7 +48,7 @@ func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) {
}

// GetComments returns comments of an issue or PR
func (n NullDownloader) GetComments(commentable Commentable) ([]*Comment, bool, error) {
func (n NullDownloader) GetComments(commentable GetCommentOptions) ([]*Comment, bool, error) {
return nil, false, ErrNotSupported{Entity: "Comments"}
}

Expand All @@ -63,8 +63,8 @@ func (n NullDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool
}

// GetReviews returns pull requests review
func (n NullDownloader) GetReviews(reviewable Reviewable) ([]*Review, error) {
return nil, ErrNotSupported{Entity: "Reviews"}
func (n NullDownloader) GetReviews(reviewable Reviewable) ([]*Review, bool, error) {
return nil, false, ErrNotSupported{Entity: "Reviews"}
}

// FormatCloneURL add authentication into remote URLs
Expand All @@ -87,3 +87,12 @@ func (n NullDownloader) FormatCloneURL(opts MigrateOptions, remoteAddr string) (
func (n NullDownloader) SupportGetRepoComments() bool {
return false
}

// SupportGetRepoReviews return true if it supports get repo pullrequest reviews
func (n NullDownloader) SupportGetRepoReviews() bool {
return false
}

// CleanUp clean the downloader temporary resources
func (n NullDownloader) CleanUp() {
}
1 change: 1 addition & 0 deletions modules/migration/pullrequest.go
Expand Up @@ -37,6 +37,7 @@ type PullRequest struct {
Reactions []*Reaction
ForeignIndex int64
Context DownloaderContext `yaml:"-"`
Assets []*Asset
EnsuredSafe bool `yaml:"ensured_safe"`
}

Expand Down
18 changes: 1 addition & 17 deletions modules/migration/release.go
Expand Up @@ -5,25 +5,9 @@
package migration

import (
"io"
"time"
)

// ReleaseAsset represents a release asset
type ReleaseAsset struct {
ID int64
Name string
ContentType *string `yaml:"content_type"`
Size *int
DownloadCount *int `yaml:"download_count"`
Created time.Time
Updated time.Time

DownloadURL *string `yaml:"download_url"` // SECURITY: It is the responsibility of downloader to make sure this is safe
// if DownloadURL is nil, the function should be invoked
DownloadFunc func() (io.ReadCloser, error) `yaml:"-"` // SECURITY: It is the responsibility of downloader to make sure this is safe
}

// Release represents a release
type Release struct {
TagName string `yaml:"tag_name"` // SECURITY: This must pass git.IsValidRefPattern
Expand All @@ -35,7 +19,7 @@ type Release struct {
PublisherID int64 `yaml:"publisher_id"`
PublisherName string `yaml:"publisher_name"`
PublisherEmail string `yaml:"publisher_email"`
Assets []*ReleaseAsset
Assets []*Asset
Created time.Time
Published time.Time
}
Expand Down
11 changes: 6 additions & 5 deletions modules/migration/retry_downloader.go
Expand Up @@ -148,15 +148,15 @@ func (d *RetryDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) {
}

// GetComments returns a repository's comments with retry
func (d *RetryDownloader) GetComments(commentable Commentable) ([]*Comment, bool, error) {
func (d *RetryDownloader) GetComments(opts GetCommentOptions) ([]*Comment, bool, error) {
var (
comments []*Comment
isEnd bool
err error
)

err = d.retry(func() error {
comments, isEnd, err = d.Downloader.GetComments(commentable)
comments, isEnd, err = d.Downloader.GetComments(opts)
return err
})

Expand All @@ -180,16 +180,17 @@ func (d *RetryDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bo
}

// GetReviews returns pull requests reviews
func (d *RetryDownloader) GetReviews(reviewable Reviewable) ([]*Review, error) {
func (d *RetryDownloader) GetReviews(reviwable Reviewable) ([]*Review, bool, error) {
var (
reviews []*Review
isEnd bool
err error
)

err = d.retry(func() error {
reviews, err = d.Downloader.GetReviews(reviewable)
reviews, isEnd, err = d.Downloader.GetReviews(reviwable)
return err
})

return reviews, err
return reviews, isEnd, err
}