aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/actions/auth.go2
-rw-r--r--services/migrations/github.go3
-rw-r--r--services/migrations/onedev.go273
3 files changed, 165 insertions, 113 deletions
diff --git a/services/actions/auth.go b/services/actions/auth.go
index 12a8fba53f..c742e19c60 100644
--- a/services/actions/auth.go
+++ b/services/actions/auth.go
@@ -53,7 +53,7 @@ func CreateAuthorizationToken(taskID, runID, jobID int64) (string, error) {
claims := actionsClaims{
RegisteredClaims: jwt.RegisteredClaims{
- ExpiresAt: jwt.NewNumericDate(now.Add(24 * time.Hour)),
+ ExpiresAt: jwt.NewNumericDate(now.Add(1*time.Hour + setting.Actions.EndlessTaskTimeout)),
NotBefore: jwt.NewNumericDate(now),
},
Scp: fmt.Sprintf("Actions.Results:%d:%d", runID, jobID),
diff --git a/services/migrations/github.go b/services/migrations/github.go
index c6cd6ea173..a8a89dce0b 100644
--- a/services/migrations/github.go
+++ b/services/migrations/github.go
@@ -354,7 +354,8 @@ func (g *GithubDownloaderV3) convertGithubRelease(ctx context.Context, rel *gith
// Prevent open redirect
if !hasBaseURL(redirectURL, g.baseURL) &&
- !hasBaseURL(redirectURL, "https://objects.githubusercontent.com/") {
+ !hasBaseURL(redirectURL, "https://objects.githubusercontent.com/") &&
+ !hasBaseURL(redirectURL, "https://release-assets.githubusercontent.com/") {
WarnAndNotice("Unexpected AssetURL for assetID[%d] in %s: %s", asset.GetID(), g, redirectURL)
return io.NopCloser(strings.NewReader(redirectURL)), nil
diff --git a/services/migrations/onedev.go b/services/migrations/onedev.go
index e052cba0cc..9917bdae3c 100644
--- a/services/migrations/onedev.go
+++ b/services/migrations/onedev.go
@@ -6,6 +6,7 @@ package migrations
import (
"context"
"fmt"
+ "io"
"net/http"
"net/url"
"strconv"
@@ -16,8 +17,12 @@ import (
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/structs"
+
+ "github.com/hashicorp/go-version"
)
+const OneDevRequiredVersion = "12.0.1"
+
var (
_ base.Downloader = &OneDevDownloader{}
_ base.DownloaderFactory = &OneDevDownloaderFactory{}
@@ -37,23 +42,14 @@ func (f *OneDevDownloaderFactory) New(ctx context.Context, opts base.MigrateOpti
return nil, err
}
- var repoName string
-
- fields := strings.Split(strings.Trim(u.Path, "/"), "/")
- if len(fields) == 2 && fields[0] == "projects" {
- repoName = fields[1]
- } else if len(fields) == 1 {
- repoName = fields[0]
- } else {
- return nil, fmt.Errorf("invalid path: %s", u.Path)
- }
+ repoPath := strings.Trim(u.Path, "/")
u.Path = ""
u.Fragment = ""
- log.Trace("Create onedev downloader. BaseURL: %v RepoName: %s", u, repoName)
+ log.Trace("Create onedev downloader. BaseURL: %v RepoPath: %s", u, repoPath)
- return NewOneDevDownloader(ctx, u, opts.AuthUsername, opts.AuthPassword, repoName), nil
+ return NewOneDevDownloader(ctx, u, opts.AuthUsername, opts.AuthPassword, repoPath), nil
}
// GitServiceType returns the type of git service
@@ -62,9 +58,9 @@ func (f *OneDevDownloaderFactory) GitServiceType() structs.GitServiceType {
}
type onedevUser struct {
- ID int64 `json:"id"`
- Name string `json:"name"`
- Email string `json:"email"`
+ ID int64
+ Name string
+ Email string
}
// OneDevDownloader implements a Downloader interface to get repository information
@@ -73,7 +69,7 @@ type OneDevDownloader struct {
base.NullDownloader
client *http.Client
baseURL *url.URL
- repoName string
+ repoPath string
repoID int64
maxIssueIndex int64
userMap map[int64]*onedevUser
@@ -81,10 +77,10 @@ type OneDevDownloader struct {
}
// NewOneDevDownloader creates a new downloader
-func NewOneDevDownloader(_ context.Context, baseURL *url.URL, username, password, repoName string) *OneDevDownloader {
+func NewOneDevDownloader(_ context.Context, baseURL *url.URL, username, password, repoPath string) *OneDevDownloader {
downloader := &OneDevDownloader{
baseURL: baseURL,
- repoName: repoName,
+ repoPath: repoPath,
client: &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
@@ -104,14 +100,14 @@ func NewOneDevDownloader(_ context.Context, baseURL *url.URL, username, password
// String implements Stringer
func (d *OneDevDownloader) String() string {
- return fmt.Sprintf("migration from oneDev server %s [%d]/%s", d.baseURL, d.repoID, d.repoName)
+ return fmt.Sprintf("migration from oneDev server %s [%d]/%s", d.baseURL, d.repoID, d.repoPath)
}
func (d *OneDevDownloader) LogString() string {
if d == nil {
return "<OneDevDownloader nil>"
}
- return fmt.Sprintf("<OneDevDownloader %s [%d]/%s>", d.baseURL, d.repoID, d.repoName)
+ return fmt.Sprintf("<OneDevDownloader %s [%d]/%s>", d.baseURL, d.repoID, d.repoPath)
}
func (d *OneDevDownloader) callAPI(ctx context.Context, endpoint string, parameter map[string]string, result any) error {
@@ -139,23 +135,54 @@ func (d *OneDevDownloader) callAPI(ctx context.Context, endpoint string, paramet
}
defer resp.Body.Close()
+ // special case to read OneDev server version, which is not valid JSON
+ if presult, ok := result.(**version.Version); ok {
+ bytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+ vers, err := version.NewVersion(string(bytes))
+ if err != nil {
+ return err
+ }
+ *presult = vers
+ return nil
+ }
+
decoder := json.NewDecoder(resp.Body)
return decoder.Decode(&result)
}
// GetRepoInfo returns repository information
func (d *OneDevDownloader) GetRepoInfo(ctx context.Context) (*base.Repository, error) {
+ // check OneDev server version
+ var serverVersion *version.Version
+ err := d.callAPI(
+ ctx,
+ "/~api/version/server",
+ nil,
+ &serverVersion,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("failed to get OneDev server version; OneDev %s or newer required", OneDevRequiredVersion)
+ }
+ requiredVersion, _ := version.NewVersion(OneDevRequiredVersion)
+ if serverVersion.LessThan(requiredVersion) {
+ return nil, fmt.Errorf("OneDev %s or newer required; currently running OneDev %s", OneDevRequiredVersion, serverVersion)
+ }
+
info := make([]struct {
ID int64 `json:"id"`
Name string `json:"name"`
+ Path string `json:"path"`
Description string `json:"description"`
}, 0, 1)
- err := d.callAPI(
+ err = d.callAPI(
ctx,
- "/api/projects",
+ "/~api/projects",
map[string]string{
- "query": `"Name" is "` + d.repoName + `"`,
+ "query": `"Path" is "` + d.repoPath + `"`,
"offset": "0",
"count": "1",
},
@@ -165,16 +192,12 @@ func (d *OneDevDownloader) GetRepoInfo(ctx context.Context) (*base.Repository, e
return nil, err
}
if len(info) != 1 {
- return nil, fmt.Errorf("Project %s not found", d.repoName)
+ return nil, fmt.Errorf("Project %s not found", d.repoPath)
}
d.repoID = info[0].ID
- cloneURL, err := d.baseURL.Parse(info[0].Name)
- if err != nil {
- return nil, err
- }
- originalURL, err := d.baseURL.Parse("/projects/" + info[0].Name)
+ cloneURL, err := d.baseURL.Parse(info[0].Path)
if err != nil {
return nil, err
}
@@ -183,25 +206,25 @@ func (d *OneDevDownloader) GetRepoInfo(ctx context.Context) (*base.Repository, e
Name: info[0].Name,
Description: info[0].Description,
CloneURL: cloneURL.String(),
- OriginalURL: originalURL.String(),
+ OriginalURL: cloneURL.String(),
}, nil
}
// GetMilestones returns milestones
func (d *OneDevDownloader) GetMilestones(ctx context.Context) ([]*base.Milestone, error) {
- rawMilestones := make([]struct {
- ID int64 `json:"id"`
- Name string `json:"name"`
- Description string `json:"description"`
- DueDate *time.Time `json:"dueDate"`
- Closed bool `json:"closed"`
- }, 0, 100)
-
- endpoint := fmt.Sprintf("/api/projects/%d/milestones", d.repoID)
+ endpoint := fmt.Sprintf("/~api/projects/%d/iterations", d.repoID)
milestones := make([]*base.Milestone, 0, 100)
offset := 0
for {
+ rawMilestones := make([]struct {
+ ID int64 `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ DueDay int64 `json:"dueDay"`
+ Closed bool `json:"closed"`
+ }, 0, 100)
+
err := d.callAPI(
ctx,
endpoint,
@@ -221,16 +244,26 @@ func (d *OneDevDownloader) GetMilestones(ctx context.Context) ([]*base.Milestone
for _, milestone := range rawMilestones {
d.milestoneMap[milestone.ID] = milestone.Name
- closed := milestone.DueDate
- if !milestone.Closed {
- closed = nil
+
+ var dueDate *time.Time
+ if milestone.DueDay != 0 {
+ d := time.Unix(milestone.DueDay*24*60*60, 0)
+ dueDate = &d
+ }
+
+ var closedDate *time.Time
+ state := "open"
+ if milestone.Closed {
+ closedDate = dueDate
+ state = "closed"
}
milestones = append(milestones, &base.Milestone{
Title: milestone.Name,
Description: milestone.Description,
- Deadline: milestone.DueDate,
- Closed: closed,
+ Deadline: dueDate,
+ Closed: closedDate,
+ State: state,
})
}
}
@@ -273,6 +306,10 @@ type onedevIssueContext struct {
// GetIssues returns issues
func (d *OneDevDownloader) GetIssues(ctx context.Context, page, perPage int) ([]*base.Issue, bool, error) {
+ type Field struct {
+ Name string `json:"name"`
+ Value string `json:"value"`
+ }
rawIssues := make([]struct {
ID int64 `json:"id"`
Number int64 `json:"number"`
@@ -281,15 +318,17 @@ func (d *OneDevDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
Description string `json:"description"`
SubmitterID int64 `json:"submitterId"`
SubmitDate time.Time `json:"submitDate"`
+ Fields []Field `json:"fields"`
}, 0, perPage)
err := d.callAPI(
ctx,
- "/api/issues",
+ "/~api/issues",
map[string]string{
- "query": `"Project" is "` + d.repoName + `"`,
- "offset": strconv.Itoa((page - 1) * perPage),
- "count": strconv.Itoa(perPage),
+ "query": `"Project" is "` + d.repoPath + `"`,
+ "offset": strconv.Itoa((page - 1) * perPage),
+ "count": strconv.Itoa(perPage),
+ "withFields": "true",
},
&rawIssues,
)
@@ -299,22 +338,8 @@ func (d *OneDevDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
issues := make([]*base.Issue, 0, len(rawIssues))
for _, issue := range rawIssues {
- fields := make([]struct {
- Name string `json:"name"`
- Value string `json:"value"`
- }, 0, 10)
- err := d.callAPI(
- ctx,
- fmt.Sprintf("/api/issues/%d/fields", issue.ID),
- nil,
- &fields,
- )
- if err != nil {
- return nil, false, err
- }
-
var label *base.Label
- for _, field := range fields {
+ for _, field := range issue.Fields {
if field.Name == "Type" {
label = &base.Label{Name: field.Value}
break
@@ -327,7 +352,7 @@ func (d *OneDevDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
}, 0, 10)
err = d.callAPI(
ctx,
- fmt.Sprintf("/api/issues/%d/milestones", issue.ID),
+ fmt.Sprintf("/~api/issues/%d/iterations", issue.ID),
nil,
&milestones,
)
@@ -383,9 +408,9 @@ func (d *OneDevDownloader) GetComments(ctx context.Context, commentable base.Com
var endpoint string
if context.IsPullRequest {
- endpoint = fmt.Sprintf("/api/pull-requests/%d/comments", commentable.GetForeignIndex())
+ endpoint = fmt.Sprintf("/~api/pulls/%d/comments", commentable.GetForeignIndex())
} else {
- endpoint = fmt.Sprintf("/api/issues/%d/comments", commentable.GetForeignIndex())
+ endpoint = fmt.Sprintf("/~api/issues/%d/comments", commentable.GetForeignIndex())
}
err := d.callAPI(
@@ -405,9 +430,9 @@ func (d *OneDevDownloader) GetComments(ctx context.Context, commentable base.Com
}, 0, 100)
if context.IsPullRequest {
- endpoint = fmt.Sprintf("/api/pull-requests/%d/changes", commentable.GetForeignIndex())
+ endpoint = fmt.Sprintf("/~api/pulls/%d/changes", commentable.GetForeignIndex())
} else {
- endpoint = fmt.Sprintf("/api/issues/%d/changes", commentable.GetForeignIndex())
+ endpoint = fmt.Sprintf("/~api/issues/%d/changes", commentable.GetForeignIndex())
}
err = d.callAPI(
@@ -468,26 +493,24 @@ func (d *OneDevDownloader) GetComments(ctx context.Context, commentable base.Com
// GetPullRequests returns pull requests
func (d *OneDevDownloader) GetPullRequests(ctx context.Context, page, perPage int) ([]*base.PullRequest, bool, error) {
rawPullRequests := make([]struct {
- ID int64 `json:"id"`
- Number int64 `json:"number"`
- Title string `json:"title"`
- SubmitterID int64 `json:"submitterId"`
- SubmitDate time.Time `json:"submitDate"`
- Description string `json:"description"`
- TargetBranch string `json:"targetBranch"`
- SourceBranch string `json:"sourceBranch"`
- BaseCommitHash string `json:"baseCommitHash"`
- CloseInfo *struct {
- Date *time.Time `json:"date"`
- Status string `json:"status"`
- }
+ ID int64 `json:"id"`
+ Number int64 `json:"number"`
+ Title string `json:"title"`
+ SubmitterID int64 `json:"submitterId"`
+ SubmitDate time.Time `json:"submitDate"`
+ Description string `json:"description"`
+ TargetBranch string `json:"targetBranch"`
+ SourceBranch string `json:"sourceBranch"`
+ BaseCommitHash string `json:"baseCommitHash"`
+ CloseDate *time.Time `json:"closeDate"`
+ Status string `json:"status"` // Possible values: OPEN, MERGED, DISCARDED
}, 0, perPage)
err := d.callAPI(
ctx,
- "/api/pull-requests",
+ "/~api/pulls",
map[string]string{
- "query": `"Target Project" is "` + d.repoName + `"`,
+ "query": `"Target Project" is "` + d.repoPath + `"`,
"offset": strconv.Itoa((page - 1) * perPage),
"count": strconv.Itoa(perPage),
},
@@ -507,7 +530,7 @@ func (d *OneDevDownloader) GetPullRequests(ctx context.Context, page, perPage in
}
err := d.callAPI(
ctx,
- fmt.Sprintf("/api/pull-requests/%d/merge-preview", pr.ID),
+ fmt.Sprintf("/~api/pulls/%d/merge-preview", pr.ID),
nil,
&mergePreview,
)
@@ -519,12 +542,12 @@ func (d *OneDevDownloader) GetPullRequests(ctx context.Context, page, perPage in
merged := false
var closeTime *time.Time
var mergedTime *time.Time
- if pr.CloseInfo != nil {
+ if pr.Status != "OPEN" {
state = "closed"
- closeTime = pr.CloseInfo.Date
- if pr.CloseInfo.Status == "MERGED" { // "DISCARDED"
+ closeTime = pr.CloseDate
+ if pr.Status == "MERGED" { // "DISCARDED"
merged = true
- mergedTime = pr.CloseInfo.Date
+ mergedTime = pr.CloseDate
}
}
poster := d.tryGetUser(ctx, pr.SubmitterID)
@@ -545,12 +568,12 @@ func (d *OneDevDownloader) GetPullRequests(ctx context.Context, page, perPage in
Head: base.PullRequestBranch{
Ref: pr.SourceBranch,
SHA: mergePreview.HeadCommitHash,
- RepoName: d.repoName,
+ RepoName: d.repoPath,
},
Base: base.PullRequestBranch{
Ref: pr.TargetBranch,
SHA: mergePreview.TargetHeadCommitHash,
- RepoName: d.repoName,
+ RepoName: d.repoPath,
},
ForeignIndex: pr.ID,
Context: onedevIssueContext{IsPullRequest: true},
@@ -566,18 +589,14 @@ func (d *OneDevDownloader) GetPullRequests(ctx context.Context, page, perPage in
// GetReviews returns pull requests reviews
func (d *OneDevDownloader) GetReviews(ctx context.Context, reviewable base.Reviewable) ([]*base.Review, error) {
rawReviews := make([]struct {
- ID int64 `json:"id"`
- UserID int64 `json:"userId"`
- Result *struct {
- Commit string `json:"commit"`
- Approved bool `json:"approved"`
- Comment string `json:"comment"`
- }
+ ID int64 `json:"id"`
+ UserID int64 `json:"userId"`
+ Status string `json:"status"` // Possible values: PENDING, APPROVED, REQUESTED_FOR_CHANGES, EXCLUDED
}, 0, 100)
err := d.callAPI(
ctx,
- fmt.Sprintf("/api/pull-requests/%d/reviews", reviewable.GetForeignIndex()),
+ fmt.Sprintf("/~api/pulls/%d/reviews", reviewable.GetForeignIndex()),
nil,
&rawReviews,
)
@@ -589,14 +608,11 @@ func (d *OneDevDownloader) GetReviews(ctx context.Context, reviewable base.Revie
for _, review := range rawReviews {
state := base.ReviewStatePending
content := ""
- if review.Result != nil {
- if len(review.Result.Comment) > 0 {
- state = base.ReviewStateCommented
- content = review.Result.Comment
- }
- if review.Result.Approved {
- state = base.ReviewStateApproved
- }
+ switch review.Status {
+ case "APPROVED":
+ state = base.ReviewStateApproved
+ case "REQUESTED_FOR_CHANGES":
+ state = base.ReviewStateChangesRequested
}
poster := d.tryGetUser(ctx, review.UserID)
@@ -620,17 +636,52 @@ func (d *OneDevDownloader) GetTopics(_ context.Context) ([]string, error) {
func (d *OneDevDownloader) tryGetUser(ctx context.Context, userID int64) *onedevUser {
user, ok := d.userMap[userID]
if !ok {
+ // get user name
+ type RawUser struct {
+ Name string `json:"name"`
+ }
+ var rawUser RawUser
err := d.callAPI(
ctx,
- fmt.Sprintf("/api/users/%d", userID),
+ fmt.Sprintf("/~api/users/%d", userID),
nil,
- &user,
+ &rawUser,
)
- if err != nil {
- user = &onedevUser{
- Name: fmt.Sprintf("User %d", userID),
+ var userName string
+ if err == nil {
+ userName = rawUser.Name
+ } else {
+ userName = fmt.Sprintf("User %d", userID)
+ }
+
+ // get (primary) user Email address
+ rawEmailAddresses := make([]struct {
+ Value string `json:"value"`
+ Primary bool `json:"primary"`
+ }, 0, 10)
+ err = d.callAPI(
+ ctx,
+ fmt.Sprintf("/~api/users/%d/email-addresses", userID),
+ nil,
+ &rawEmailAddresses,
+ )
+ var userEmail string
+ if err == nil {
+ for _, email := range rawEmailAddresses {
+ if userEmail == "" || email.Primary {
+ userEmail = email.Value
+ }
+ if email.Primary {
+ break
+ }
}
}
+
+ user = &onedevUser{
+ ID: userID,
+ Name: userName,
+ Email: userEmail,
+ }
d.userMap[userID] = user
}