aboutsummaryrefslogtreecommitdiffstats
path: root/services/convert
diff options
context:
space:
mode:
Diffstat (limited to 'services/convert')
-rw-r--r--services/convert/convert.go286
-rw-r--r--services/convert/git_commit_test.go2
-rw-r--r--services/convert/pull.go125
-rw-r--r--services/convert/pull_review_test.go4
-rw-r--r--services/convert/pull_test.go9
-rw-r--r--services/convert/release_test.go4
-rw-r--r--services/convert/repository.go8
-rw-r--r--services/convert/status.go38
-rw-r--r--services/convert/user_test.go4
-rw-r--r--services/convert/utils_test.go8
10 files changed, 370 insertions, 118 deletions
diff --git a/services/convert/convert.go b/services/convert/convert.go
index ac2680766c..0de3822140 100644
--- a/services/convert/convert.go
+++ b/services/convert/convert.go
@@ -5,8 +5,11 @@
package convert
import (
+ "bytes"
"context"
"fmt"
+ "net/url"
+ "path"
"strconv"
"strings"
"time"
@@ -14,6 +17,7 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
@@ -22,6 +26,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@@ -30,6 +35,9 @@ import (
"code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/gitdiff"
+
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "github.com/nektos/act/pkg/model"
)
// ToEmail convert models.EmailAddress to api.Email
@@ -141,7 +149,7 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo
mergeWhitelistUsernames := getWhitelistEntities(readers, bp.MergeWhitelistUserIDs)
approvalsWhitelistUsernames := getWhitelistEntities(readers, bp.ApprovalsWhitelistUserIDs)
- teamReaders, err := organization.OrgFromUser(repo.Owner).TeamsWithAccessToRepo(ctx, repo.ID, perm.AccessModeRead)
+ teamReaders, err := organization.GetTeamsWithAccessToAnyRepoUnit(ctx, repo.Owner.ID, repo.ID, perm.AccessModeRead, unit.TypeCode, unit.TypePullRequests)
if err != nil {
log.Error("Repo.Owner.TeamsWithAccessToRepo: %v", err)
}
@@ -195,13 +203,22 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo
// ToTag convert a git.Tag to an api.Tag
func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
+ tarballURL := util.URLJoin(repo.HTMLURL(), "archive", t.Name+".tar.gz")
+ zipballURL := util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip")
+
+ // Archive URLs are "" if the download feature is disabled
+ if setting.Repository.DisableDownloadSourceArchives {
+ tarballURL = ""
+ zipballURL = ""
+ }
+
return &api.Tag{
Name: t.Name,
Message: strings.TrimSpace(t.Message),
ID: t.ID.String(),
Commit: ToCommitMeta(repo, t),
- ZipballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip"),
- TarballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".tar.gz"),
+ ZipballURL: zipballURL,
+ TarballURL: tarballURL,
}
}
@@ -230,6 +247,242 @@ func ToActionTask(ctx context.Context, t *actions_model.ActionTask) (*api.Action
}, nil
}
+func ToActionWorkflowRun(ctx context.Context, repo *repo_model.Repository, run *actions_model.ActionRun) (*api.ActionWorkflowRun, error) {
+ err := run.LoadAttributes(ctx)
+ if err != nil {
+ return nil, err
+ }
+ status, conclusion := ToActionsStatus(run.Status)
+ return &api.ActionWorkflowRun{
+ ID: run.ID,
+ URL: fmt.Sprintf("%s/actions/runs/%d", repo.APIURL(), run.ID),
+ HTMLURL: run.HTMLURL(),
+ RunNumber: run.Index,
+ StartedAt: run.Started.AsLocalTime(),
+ CompletedAt: run.Stopped.AsLocalTime(),
+ Event: string(run.Event),
+ DisplayTitle: run.Title,
+ HeadBranch: git.RefName(run.Ref).BranchName(),
+ HeadSha: run.CommitSHA,
+ Status: status,
+ Conclusion: conclusion,
+ Path: fmt.Sprintf("%s@%s", run.WorkflowID, run.Ref),
+ Repository: ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeNone}),
+ TriggerActor: ToUser(ctx, run.TriggerUser, nil),
+ // We do not have a way to get a different User for the actor than the trigger user
+ Actor: ToUser(ctx, run.TriggerUser, nil),
+ }, nil
+}
+
+func ToWorkflowRunAction(status actions_model.Status) string {
+ var action string
+ switch status {
+ case actions_model.StatusWaiting, actions_model.StatusBlocked:
+ action = "requested"
+ case actions_model.StatusRunning:
+ action = "in_progress"
+ }
+ if status.IsDone() {
+ action = "completed"
+ }
+ return action
+}
+
+func ToActionsStatus(status actions_model.Status) (string, string) {
+ var action string
+ var conclusion string
+ switch status {
+ // This is a naming conflict of the webhook between Gitea and GitHub Actions
+ case actions_model.StatusWaiting:
+ action = "queued"
+ case actions_model.StatusBlocked:
+ action = "waiting"
+ case actions_model.StatusRunning:
+ action = "in_progress"
+ }
+ if status.IsDone() {
+ action = "completed"
+ switch status {
+ case actions_model.StatusSuccess:
+ conclusion = "success"
+ case actions_model.StatusCancelled:
+ conclusion = "cancelled"
+ case actions_model.StatusFailure:
+ conclusion = "failure"
+ case actions_model.StatusSkipped:
+ conclusion = "skipped"
+ }
+ }
+ return action, conclusion
+}
+
+// ToActionWorkflowJob convert a actions_model.ActionRunJob to an api.ActionWorkflowJob
+// task is optional and can be nil
+func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task *actions_model.ActionTask, job *actions_model.ActionRunJob) (*api.ActionWorkflowJob, error) {
+ err := job.LoadAttributes(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ jobIndex := 0
+ jobs, err := actions_model.GetRunJobsByRunID(ctx, job.RunID)
+ if err != nil {
+ return nil, err
+ }
+ for i, j := range jobs {
+ if j.ID == job.ID {
+ jobIndex = i
+ break
+ }
+ }
+
+ status, conclusion := ToActionsStatus(job.Status)
+ var runnerID int64
+ var runnerName string
+ var steps []*api.ActionWorkflowStep
+
+ if job.TaskID != 0 {
+ if task == nil {
+ task, _, err = db.GetByID[actions_model.ActionTask](ctx, job.TaskID)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ runnerID = task.RunnerID
+ if runner, ok, _ := db.GetByID[actions_model.ActionRunner](ctx, runnerID); ok {
+ runnerName = runner.Name
+ }
+ for i, step := range task.Steps {
+ stepStatus, stepConclusion := ToActionsStatus(job.Status)
+ steps = append(steps, &api.ActionWorkflowStep{
+ Name: step.Name,
+ Number: int64(i),
+ Status: stepStatus,
+ Conclusion: stepConclusion,
+ StartedAt: step.Started.AsTime().UTC(),
+ CompletedAt: step.Stopped.AsTime().UTC(),
+ })
+ }
+ }
+
+ return &api.ActionWorkflowJob{
+ ID: job.ID,
+ // missing api endpoint for this location
+ URL: fmt.Sprintf("%s/actions/jobs/%d", repo.APIURL(), job.ID),
+ HTMLURL: fmt.Sprintf("%s/jobs/%d", job.Run.HTMLURL(), jobIndex),
+ RunID: job.RunID,
+ // Missing api endpoint for this location, artifacts are available under a nested url
+ RunURL: fmt.Sprintf("%s/actions/runs/%d", repo.APIURL(), job.RunID),
+ Name: job.Name,
+ Labels: job.RunsOn,
+ RunAttempt: job.Attempt,
+ HeadSha: job.Run.CommitSHA,
+ HeadBranch: git.RefName(job.Run.Ref).BranchName(),
+ Status: status,
+ Conclusion: conclusion,
+ RunnerID: runnerID,
+ RunnerName: runnerName,
+ Steps: steps,
+ CreatedAt: job.Created.AsTime().UTC(),
+ StartedAt: job.Started.AsTime().UTC(),
+ CompletedAt: job.Stopped.AsTime().UTC(),
+ }, nil
+}
+
+func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, folder string, entry *git.TreeEntry) *api.ActionWorkflow {
+ cfgUnit := repo.MustGetUnit(ctx, unit.TypeActions)
+ cfg := cfgUnit.ActionsConfig()
+
+ defaultBranch, _ := commit.GetBranchName()
+
+ workflowURL := fmt.Sprintf("%s/actions/workflows/%s", repo.APIURL(), util.PathEscapeSegments(entry.Name()))
+ workflowRepoURL := fmt.Sprintf("%s/src/branch/%s/%s/%s", repo.HTMLURL(ctx), util.PathEscapeSegments(defaultBranch), util.PathEscapeSegments(folder), util.PathEscapeSegments(entry.Name()))
+ badgeURL := fmt.Sprintf("%s/actions/workflows/%s/badge.svg?branch=%s", repo.HTMLURL(ctx), util.PathEscapeSegments(entry.Name()), url.QueryEscape(repo.DefaultBranch))
+
+ // See https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#get-a-workflow
+ // State types:
+ // - active
+ // - deleted
+ // - disabled_fork
+ // - disabled_inactivity
+ // - disabled_manually
+ state := "active"
+ if cfg.IsWorkflowDisabled(entry.Name()) {
+ state = "disabled_manually"
+ }
+
+ // The CreatedAt and UpdatedAt fields currently reflect the timestamp of the latest commit, which can later be refined
+ // by retrieving the first and last commits for the file history. The first commit would indicate the creation date,
+ // while the last commit would represent the modification date. The DeletedAt could be determined by identifying
+ // the last commit where the file existed. However, this implementation has not been done here yet, as it would likely
+ // cause a significant performance degradation.
+ createdAt := commit.Author.When
+ updatedAt := commit.Author.When
+
+ content, err := actions.GetContentFromEntry(entry)
+ name := entry.Name()
+ if err == nil {
+ workflow, err := model.ReadWorkflow(bytes.NewReader(content))
+ if err == nil {
+ // Only use the name when specified in the workflow file
+ if workflow.Name != "" {
+ name = workflow.Name
+ }
+ } else {
+ log.Error("getActionWorkflowEntry: Failed to parse workflow: %v", err)
+ }
+ } else {
+ log.Error("getActionWorkflowEntry: Failed to get content from entry: %v", err)
+ }
+
+ return &api.ActionWorkflow{
+ ID: entry.Name(),
+ Name: name,
+ Path: path.Join(folder, entry.Name()),
+ State: state,
+ CreatedAt: createdAt,
+ UpdatedAt: updatedAt,
+ URL: workflowURL,
+ HTMLURL: workflowRepoURL,
+ BadgeURL: badgeURL,
+ }
+}
+
+func ListActionWorkflows(ctx context.Context, gitrepo *git.Repository, repo *repo_model.Repository) ([]*api.ActionWorkflow, error) {
+ defaultBranchCommit, err := gitrepo.GetBranchCommit(repo.DefaultBranch)
+ if err != nil {
+ return nil, err
+ }
+
+ folder, entries, err := actions.ListWorkflows(defaultBranchCommit)
+ if err != nil {
+ return nil, err
+ }
+
+ workflows := make([]*api.ActionWorkflow, len(entries))
+ for i, entry := range entries {
+ workflows[i] = getActionWorkflowEntry(ctx, repo, defaultBranchCommit, folder, entry)
+ }
+
+ return workflows, nil
+}
+
+func GetActionWorkflow(ctx context.Context, gitrepo *git.Repository, repo *repo_model.Repository, workflowID string) (*api.ActionWorkflow, error) {
+ entries, err := ListActionWorkflows(ctx, gitrepo, repo)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, entry := range entries {
+ if entry.ID == workflowID {
+ return entry, nil
+ }
+ }
+
+ return nil, util.NewNotExistErrorf("workflow %q not found", workflowID)
+}
+
// ToActionArtifact convert a actions_model.ActionArtifact to an api.ActionArtifact
func ToActionArtifact(repo *repo_model.Repository, art *actions_model.ActionArtifact) (*api.ActionArtifact, error) {
url := fmt.Sprintf("%s/actions/artifacts/%d", repo.APIURL(), art.ID)
@@ -252,6 +505,30 @@ func ToActionArtifact(repo *repo_model.Repository, art *actions_model.ActionArti
}, nil
}
+func ToActionRunner(ctx context.Context, runner *actions_model.ActionRunner) *api.ActionRunner {
+ status := runner.Status()
+ apiStatus := "offline"
+ if runner.IsOnline() {
+ apiStatus = "online"
+ }
+ labels := make([]*api.ActionRunnerLabel, len(runner.AgentLabels))
+ for i, label := range runner.AgentLabels {
+ labels[i] = &api.ActionRunnerLabel{
+ ID: int64(i),
+ Name: label,
+ Type: "custom",
+ }
+ }
+ return &api.ActionRunner{
+ ID: runner.ID,
+ Name: runner.Name,
+ Status: apiStatus,
+ Busy: status == runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE,
+ Ephemeral: runner.Ephemeral,
+ Labels: labels,
+ }
+}
+
// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_service.ParseCommitWithSignature(ctx, c)
@@ -281,6 +558,7 @@ func ToPublicKey(apiLink string, key *asymkey_model.PublicKey) *api.PublicKey {
Title: key.Name,
Fingerprint: key.Fingerprint,
Created: key.CreatedUnix.AsTime(),
+ Updated: key.UpdatedUnix.AsTime(),
}
}
@@ -449,7 +727,7 @@ func ToTagProtection(ctx context.Context, pt *git_model.ProtectedTag, repo *repo
whitelistUsernames := getWhitelistEntities(readers, pt.AllowlistUserIDs)
- teamReaders, err := organization.OrgFromUser(repo.Owner).TeamsWithAccessToRepo(ctx, repo.ID, perm.AccessModeRead)
+ teamReaders, err := organization.GetTeamsWithAccessToAnyRepoUnit(ctx, repo.Owner.ID, repo.ID, perm.AccessModeRead, unit.TypeCode, unit.TypePullRequests)
if err != nil {
log.Error("Repo.Owner.TeamsWithAccessToRepo: %v", err)
}
diff --git a/services/convert/git_commit_test.go b/services/convert/git_commit_test.go
index 73cb5e8c71..ad1cc0eca3 100644
--- a/services/convert/git_commit_test.go
+++ b/services/convert/git_commit_test.go
@@ -33,7 +33,7 @@ func TestToCommitMeta(t *testing.T) {
commitMeta := ToCommitMeta(headRepo, tag)
assert.NotNil(t, commitMeta)
- assert.EqualValues(t, &api.CommitMeta{
+ assert.Equal(t, &api.CommitMeta{
SHA: sha1.EmptyObjectID().String(),
URL: util.URLJoin(headRepo.APIURL(), "git/commits", sha1.EmptyObjectID().String()),
Created: time.Unix(0, 0),
diff --git a/services/convert/pull.go b/services/convert/pull.go
index 928534ce5e..4acbd880dc 100644
--- a/services/convert/pull.go
+++ b/services/convert/pull.go
@@ -14,6 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/cachegroup"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
@@ -28,8 +29,8 @@ import (
// Optional - Merger
func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) *api.PullRequest {
var (
- baseBranch *git.Branch
- headBranch *git.Branch
+ baseBranch string
+ headBranch string
baseCommit *git.Commit
err error
)
@@ -60,14 +61,14 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
doerID = doer.ID
}
- const repoDoerPermCacheKey = "repo_doer_perm_cache"
- p, err := cache.GetWithContextCache(ctx, repoDoerPermCacheKey, fmt.Sprintf("%d_%d", pr.BaseRepoID, doerID),
- func() (access_model.Permission, error) {
+ repoUserPerm, err := cache.GetWithContextCache(ctx, cachegroup.RepoUserPermission, fmt.Sprintf("%d-%d", pr.BaseRepoID, doerID),
+ func(ctx context.Context, _ string) (access_model.Permission, error) {
return access_model.GetUserRepoPermission(ctx, pr.BaseRepo, doer)
- })
+ },
+ )
if err != nil {
log.Error("GetUserRepoPermission[%d]: %v", pr.BaseRepoID, err)
- p.AccessMode = perm.AccessModeNone
+ repoUserPerm.AccessMode = perm.AccessModeNone
}
apiPullRequest := &api.PullRequest{
@@ -107,11 +108,11 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
RepoID: pr.BaseRepoID,
- Repository: ToRepo(ctx, pr.BaseRepo, p),
+ Repository: ToRepo(ctx, pr.BaseRepo, repoUserPerm),
},
Head: &api.PRBranchInfo{
Name: pr.HeadBranch,
- Ref: fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index),
+ Ref: pr.GetGitHeadRefName(),
RepoID: -1,
},
}
@@ -150,16 +151,16 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
}
defer gitRepo.Close()
- baseBranch, err = gitRepo.GetBranch(pr.BaseBranch)
- if err != nil && !git.IsErrBranchNotExist(err) {
+ exist, err := git_model.IsBranchExist(ctx, pr.BaseRepoID, pr.BaseBranch)
+ if err != nil {
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
return nil
}
- if err == nil {
- baseCommit, err = baseBranch.GetCommit()
+ if exist {
+ baseCommit, err = gitRepo.GetBranchCommit(pr.BaseBranch)
if err != nil && !git.IsErrNotExist(err) {
- log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
+ log.Error("GetCommit[%s]: %v", baseBranch, err)
return nil
}
@@ -169,16 +170,9 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
}
if pr.Flow == issues_model.PullRequestFlowAGit {
- gitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
- if err != nil {
- log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err)
- return nil
- }
- defer gitRepo.Close()
-
- apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
+ apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
if err != nil {
- log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
+ log.Error("GetRefCommitID[%s]: %v", pr.GetGitHeadRefName(), err)
return nil
}
apiPullRequest.Head.RepoID = pr.BaseRepoID
@@ -203,8 +197,8 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
}
defer headGitRepo.Close()
- headBranch, err = headGitRepo.GetBranch(pr.HeadBranch)
- if err != nil && !git.IsErrBranchNotExist(err) {
+ exist, err = git_model.IsBranchExist(ctx, pr.HeadRepoID, pr.HeadBranch)
+ if err != nil {
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
return nil
}
@@ -215,7 +209,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
endCommitID string
)
- if git.IsErrBranchNotExist(err) {
+ if !exist {
headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref)
if err != nil && !git.IsErrNotExist(err) {
log.Error("GetCommit[%s]: %v", pr.HeadBranch, err)
@@ -226,9 +220,9 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
endCommitID = headCommitID
}
} else {
- commit, err := headBranch.GetCommit()
+ commit, err := headGitRepo.GetBranchCommit(pr.HeadBranch)
if err != nil && !git.IsErrNotExist(err) {
- log.Error("GetCommit[%s]: %v", headBranch.Name, err)
+ log.Error("GetCommit[%s]: %v", headBranch, err)
return nil
}
if err == nil {
@@ -389,7 +383,7 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
},
Head: &api.PRBranchInfo{
Name: pr.HeadBranch,
- Ref: fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index),
+ Ref: pr.GetGitHeadRefName(),
RepoID: -1,
},
}
@@ -422,72 +416,43 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
return nil, err
}
}
-
if baseBranch != nil {
apiPullRequest.Base.Sha = baseBranch.CommitID
}
+ if pr.HeadRepoID == pr.BaseRepoID {
+ apiPullRequest.Head.Repository = apiPullRequest.Base.Repository
+ }
- if pr.Flow == issues_model.PullRequestFlowAGit {
- apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
+ // pull request head branch, both repository and branch could not exist
+ if pr.HeadRepo != nil {
+ apiPullRequest.Head.RepoID = pr.HeadRepo.ID
+ exist, err := git_model.IsBranchExist(ctx, pr.HeadRepo.ID, pr.HeadBranch)
if err != nil {
- log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
+ log.Error("IsBranchExist[%d]: %v", pr.HeadRepo.ID, err)
return nil, err
}
- apiPullRequest.Head.RepoID = pr.BaseRepoID
- apiPullRequest.Head.Repository = apiPullRequest.Base.Repository
- apiPullRequest.Head.Name = ""
- }
-
- var headGitRepo *git.Repository
- if pr.HeadRepo != nil && pr.Flow == issues_model.PullRequestFlowGithub {
- if pr.HeadRepoID == pr.BaseRepoID {
- apiPullRequest.Head.RepoID = pr.HeadRepo.ID
- apiPullRequest.Head.Repository = apiRepo
- headGitRepo = gitRepo
- } else {
+ if exist {
+ apiPullRequest.Head.Ref = pr.HeadBranch
+ }
+ if pr.HeadRepoID != pr.BaseRepoID {
p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer)
if err != nil {
log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err)
p.AccessMode = perm.AccessModeNone
}
-
- apiPullRequest.Head.RepoID = pr.HeadRepo.ID
apiPullRequest.Head.Repository = ToRepo(ctx, pr.HeadRepo, p)
-
- headGitRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo)
- if err != nil {
- log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err)
- return nil, err
- }
- defer headGitRepo.Close()
- }
-
- headBranch, err := headGitRepo.GetBranch(pr.HeadBranch)
- if err != nil && !git.IsErrBranchNotExist(err) {
- log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
- return nil, err
}
+ }
+ if apiPullRequest.Head.Ref == "" {
+ apiPullRequest.Head.Ref = pr.GetGitHeadRefName()
+ }
- if git.IsErrBranchNotExist(err) {
- headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref)
- if err != nil && !git.IsErrNotExist(err) {
- log.Error("GetCommit[%s]: %v", pr.HeadBranch, err)
- return nil, err
- }
- if err == nil {
- apiPullRequest.Head.Sha = headCommitID
- }
- } else {
- commit, err := headBranch.GetCommit()
- if err != nil && !git.IsErrNotExist(err) {
- log.Error("GetCommit[%s]: %v", headBranch.Name, err)
- return nil, err
- }
- if err == nil {
- apiPullRequest.Head.Ref = pr.HeadBranch
- apiPullRequest.Head.Sha = commit.ID.String()
- }
- }
+ if pr.Flow == issues_model.PullRequestFlowAGit {
+ apiPullRequest.Head.Name = ""
+ }
+ apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
+ if err != nil {
+ log.Error("GetRefCommitID[%s]: %v", pr.GetGitHeadRefName(), err)
}
if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {
diff --git a/services/convert/pull_review_test.go b/services/convert/pull_review_test.go
index a1296fafd4..d0a077ab24 100644
--- a/services/convert/pull_review_test.go
+++ b/services/convert/pull_review_test.go
@@ -19,8 +19,8 @@ func Test_ToPullReview(t *testing.T) {
reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 6})
- assert.EqualValues(t, reviewer.ID, review.ReviewerID)
- assert.EqualValues(t, issues_model.ReviewTypePending, review.Type)
+ assert.Equal(t, reviewer.ID, review.ReviewerID)
+ assert.Equal(t, issues_model.ReviewTypePending, review.Type)
reviewList := []*issues_model.Review{review}
diff --git a/services/convert/pull_test.go b/services/convert/pull_test.go
index e069fa4a68..dfbe24d184 100644
--- a/services/convert/pull_test.go
+++ b/services/convert/pull_test.go
@@ -27,7 +27,7 @@ func TestPullRequest_APIFormat(t *testing.T) {
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil)
assert.NotNil(t, apiPullRequest)
- assert.EqualValues(t, &structs.PRBranchInfo{
+ assert.Equal(t, &structs.PRBranchInfo{
Name: "branch1",
Ref: "refs/pull/2/head",
Sha: "4a357436d925b5c974181ff12a994538ddc5a269",
@@ -46,4 +46,11 @@ func TestPullRequest_APIFormat(t *testing.T) {
assert.NotNil(t, apiPullRequest)
assert.Nil(t, apiPullRequest.Head.Repository)
assert.EqualValues(t, -1, apiPullRequest.Head.RepoID)
+
+ apiPullRequests, err := ToAPIPullRequests(git.DefaultContext, pr.BaseRepo, []*issues_model.PullRequest{pr}, nil)
+ assert.NoError(t, err)
+ assert.Len(t, apiPullRequests, 1)
+ assert.NotNil(t, apiPullRequests[0])
+ assert.Nil(t, apiPullRequests[0].Head.Repository)
+ assert.EqualValues(t, -1, apiPullRequests[0].Head.RepoID)
}
diff --git a/services/convert/release_test.go b/services/convert/release_test.go
index 201b27e16d..bb618c9ca3 100644
--- a/services/convert/release_test.go
+++ b/services/convert/release_test.go
@@ -23,6 +23,6 @@ func TestRelease_ToRelease(t *testing.T) {
apiRelease := ToAPIRelease(db.DefaultContext, repo1, release1)
assert.NotNil(t, apiRelease)
assert.EqualValues(t, 1, apiRelease.ID)
- assert.EqualValues(t, "https://try.gitea.io/api/v1/repos/user2/repo1/releases/1", apiRelease.URL)
- assert.EqualValues(t, "https://try.gitea.io/api/v1/repos/user2/repo1/releases/1/assets", apiRelease.UploadURL)
+ assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/releases/1", apiRelease.URL)
+ assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/releases/1/assets", apiRelease.UploadURL)
}
diff --git a/services/convert/repository.go b/services/convert/repository.go
index 7dfdfd2179..a364591bb8 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -98,6 +98,8 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
allowSquash := false
allowFastForwardOnly := false
allowRebaseUpdate := false
+ allowManualMerge := true
+ autodetectManualMerge := false
defaultDeleteBranchAfterMerge := false
defaultMergeStyle := repo_model.MergeStyleMerge
defaultAllowMaintainerEdit := false
@@ -111,6 +113,8 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
allowSquash = config.AllowSquash
allowFastForwardOnly = config.AllowFastForwardOnly
allowRebaseUpdate = config.AllowRebaseUpdate
+ allowManualMerge = config.AllowManualMerge
+ autodetectManualMerge = config.AutodetectManualMerge
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
defaultMergeStyle = config.GetDefaultMergeStyle()
defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit
@@ -235,6 +239,8 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
AllowSquash: allowSquash,
AllowFastForwardOnly: allowFastForwardOnly,
AllowRebaseUpdate: allowRebaseUpdate,
+ AllowManualMerge: allowManualMerge,
+ AutodetectManualMerge: autodetectManualMerge,
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
DefaultMergeStyle: string(defaultMergeStyle),
DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit,
@@ -245,7 +251,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
RepoTransfer: transfer,
Topics: util.SliceNilAsEmpty(repo.Topics),
ObjectFormatName: repo.ObjectFormatName,
- Licenses: repoLicenses.StringList(),
+ Licenses: util.SliceNilAsEmpty(repoLicenses.StringList()),
}
}
diff --git a/services/convert/status.go b/services/convert/status.go
index 6cef63c1cd..b4864a0307 100644
--- a/services/convert/status.go
+++ b/services/convert/status.go
@@ -5,6 +5,7 @@ package convert
import (
"context"
+ "net/url"
git_model "code.gitea.io/gitea/models/git"
user_model "code.gitea.io/gitea/models/user"
@@ -32,34 +33,29 @@ func ToCommitStatus(ctx context.Context, status *git_model.CommitStatus) *api.Co
return apiStatus
}
+func ToCommitStatuses(ctx context.Context, statuses []*git_model.CommitStatus) []*api.CommitStatus {
+ apiStatuses := make([]*api.CommitStatus, len(statuses))
+ for i, status := range statuses {
+ apiStatuses[i] = ToCommitStatus(ctx, status)
+ }
+ return apiStatuses
+}
+
// ToCombinedStatus converts List of CommitStatus to a CombinedStatus
func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, repo *api.Repository) *api.CombinedStatus {
if len(statuses) == 0 {
return nil
}
- retStatus := &api.CombinedStatus{
- SHA: statuses[0].SHA,
+ combinedStatus := git_model.CalcCommitStatus(statuses)
+
+ return &api.CombinedStatus{
+ State: combinedStatus.State,
+ Statuses: ToCommitStatuses(ctx, statuses),
+ SHA: combinedStatus.SHA,
TotalCount: len(statuses),
Repository: repo,
- URL: "",
+ CommitURL: repo.URL + "/commits/" + url.PathEscape(combinedStatus.SHA),
+ URL: repo.URL + "/commits/" + url.PathEscape(combinedStatus.SHA) + "/status",
}
-
- retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses))
- for _, status := range statuses {
- retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status))
- if retStatus.State == "" || status.State.NoBetterThan(retStatus.State) {
- retStatus.State = status.State
- }
- }
- // According to https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference
- // > Additionally, a combined state is returned. The state is one of:
- // > failure if any of the contexts report as error or failure
- // > pending if there are no statuses or a context is pending
- // > success if the latest status for all contexts is success
- if retStatus.State.IsError() {
- retStatus.State = api.CommitStatusFailure
- }
-
- return retStatus
}
diff --git a/services/convert/user_test.go b/services/convert/user_test.go
index 4b1effc7aa..199d500732 100644
--- a/services/convert/user_test.go
+++ b/services/convert/user_test.go
@@ -30,11 +30,11 @@ func TestUser_ToUser(t *testing.T) {
apiUser = toUser(db.DefaultContext, user1, false, false)
assert.False(t, apiUser.IsAdmin)
- assert.EqualValues(t, api.VisibleTypePublic.String(), apiUser.Visibility)
+ assert.Equal(t, api.VisibleTypePublic.String(), apiUser.Visibility)
user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate})
apiUser = toUser(db.DefaultContext, user31, true, true)
assert.False(t, apiUser.IsAdmin)
- assert.EqualValues(t, api.VisibleTypePrivate.String(), apiUser.Visibility)
+ assert.Equal(t, api.VisibleTypePrivate.String(), apiUser.Visibility)
}
diff --git a/services/convert/utils_test.go b/services/convert/utils_test.go
index a8363ec6bd..7965624e2b 100644
--- a/services/convert/utils_test.go
+++ b/services/convert/utils_test.go
@@ -10,10 +10,10 @@ import (
)
func TestToCorrectPageSize(t *testing.T) {
- assert.EqualValues(t, 30, ToCorrectPageSize(0))
- assert.EqualValues(t, 30, ToCorrectPageSize(-10))
- assert.EqualValues(t, 20, ToCorrectPageSize(20))
- assert.EqualValues(t, 50, ToCorrectPageSize(100))
+ assert.Equal(t, 30, ToCorrectPageSize(0))
+ assert.Equal(t, 30, ToCorrectPageSize(-10))
+ assert.Equal(t, 20, ToCorrectPageSize(20))
+ assert.Equal(t, 50, ToCorrectPageSize(100))
}
func TestToGitServiceType(t *testing.T) {