mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-31 16:15:13 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// HashAvatar will generate a unique string, which ensures that when there's a
|
||||
// different unique ID while the data is the same, it will generate a different
|
||||
// output. It will generate the output according to:
|
||||
// HEX(HASH(uniqueID || - || data))
|
||||
// The hash being used is SHA256.
|
||||
// The sole purpose of the unique ID is to generate a distinct hash Such that
|
||||
// two unique IDs with the same data will have a different hash output.
|
||||
// The "-" byte is important to ensure that data cannot be modified such that
|
||||
// the first byte is a number, which could lead to a "collision" with the hash
|
||||
// of another unique ID.
|
||||
func HashAvatar(uniqueID int64, data []byte) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(strconv.FormatInt(uniqueID, 10)))
|
||||
h.Write([]byte{'-'})
|
||||
h.Write(data)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
Vendored
-33
@@ -45,39 +45,6 @@ func GetCache() mc.Cache {
|
||||
return conn
|
||||
}
|
||||
|
||||
// Get returns the key value from cache with callback when no key exists in cache
|
||||
func Get[V interface{}](key string, getFunc func() (V, error)) (V, error) {
|
||||
if conn == nil || setting.CacheService.TTL == 0 {
|
||||
return getFunc()
|
||||
}
|
||||
|
||||
cached := conn.Get(key)
|
||||
if value, ok := cached.(V); ok {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
value, err := getFunc()
|
||||
if err != nil {
|
||||
return value, err
|
||||
}
|
||||
|
||||
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
|
||||
}
|
||||
|
||||
// Set updates and returns the key value in the cache with callback. The old value is only removed if the updateFunc() is successful
|
||||
func Set[V interface{}](key string, valueFunc func() (V, error)) (V, error) {
|
||||
if conn == nil || setting.CacheService.TTL == 0 {
|
||||
return valueFunc()
|
||||
}
|
||||
|
||||
value, err := valueFunc()
|
||||
if err != nil {
|
||||
return value, err
|
||||
}
|
||||
|
||||
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
|
||||
}
|
||||
|
||||
// GetString returns the key value from cache with callback when no key exists in cache
|
||||
func GetString(key string, getFunc func() (string, error)) (string, error) {
|
||||
if conn == nil || setting.CacheService.TTL == 0 {
|
||||
|
||||
@@ -219,7 +219,13 @@ func (ctx *APIContext) CheckForOTP() {
|
||||
func APIAuth(authMethod auth_service.Method) func(*APIContext) {
|
||||
return func(ctx *APIContext) {
|
||||
// Get user from session if logged in.
|
||||
ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
|
||||
var err error
|
||||
ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnauthorized, "APIAuth", err)
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Doer != nil {
|
||||
if ctx.Locale.Language() != ctx.Doer.Language {
|
||||
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
|
||||
@@ -387,7 +393,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if len(refName) == 40 {
|
||||
} else if len(refName) == git.SHAFullLength {
|
||||
ctx.Repo.CommitID = refName
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
|
||||
if err != nil {
|
||||
|
||||
@@ -662,7 +662,13 @@ func getCsrfOpts() CsrfOptions {
|
||||
// Auth converts auth.Auth as a middleware
|
||||
func Auth(authMethod auth.Method) func(*Context) {
|
||||
return func(ctx *Context) {
|
||||
ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
|
||||
var err error
|
||||
ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
|
||||
if err != nil {
|
||||
log.Error("Failed to verify user %v: %v", ctx.Req.RemoteAddr, err)
|
||||
ctx.Error(http.StatusUnauthorized, "Verify")
|
||||
return
|
||||
}
|
||||
if ctx.Doer != nil {
|
||||
if ctx.Locale.Language() != ctx.Doer.Language {
|
||||
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
|
||||
|
||||
@@ -126,7 +126,7 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use
|
||||
userCanPush := true
|
||||
requireSigned := false
|
||||
if protectedBranch != nil {
|
||||
userCanPush = protectedBranch.CanUserPush(doer.ID)
|
||||
userCanPush = protectedBranch.CanUserPush(ctx, doer.ID)
|
||||
requireSigned = protectedBranch.RequireSignedCommits
|
||||
}
|
||||
|
||||
@@ -817,7 +817,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
|
||||
}
|
||||
// For legacy and API support only full commit sha
|
||||
parts := strings.Split(path, "/")
|
||||
if len(parts) > 0 && len(parts[0]) == 40 {
|
||||
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
|
||||
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
|
||||
return parts[0]
|
||||
}
|
||||
@@ -831,7 +831,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
|
||||
if len(ref) == 0 {
|
||||
// maybe it's a renamed branch
|
||||
return getRefNameFromPath(ctx, path, func(s string) bool {
|
||||
b, exist, err := git_model.FindRenamedBranch(ctx.Repo.Repository.ID, s)
|
||||
b, exist, err := git_model.FindRenamedBranch(ctx, ctx.Repo.Repository.ID, s)
|
||||
if err != nil {
|
||||
log.Error("FindRenamedBranch", err)
|
||||
return false
|
||||
@@ -853,7 +853,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
|
||||
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
|
||||
case RepoRefCommit:
|
||||
parts := strings.Split(path, "/")
|
||||
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= 40 {
|
||||
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
|
||||
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
|
||||
return parts[0]
|
||||
}
|
||||
@@ -962,7 +962,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if len(refName) >= 7 && len(refName) <= 40 {
|
||||
} else if len(refName) >= 7 && len(refName) <= git.SHAFullLength {
|
||||
ctx.Repo.IsViewCommit = true
|
||||
ctx.Repo.CommitID = refName
|
||||
|
||||
@@ -972,7 +972,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
|
||||
return
|
||||
}
|
||||
// If short commit ID add canonical link header
|
||||
if len(refName) < 40 {
|
||||
if len(refName) < git.SHAFullLength {
|
||||
ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
|
||||
util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToAttachment converts models.Attachment to api.Attachment
|
||||
func ToAttachment(a *repo_model.Attachment) *api.Attachment {
|
||||
return &api.Attachment{
|
||||
ID: a.ID,
|
||||
Name: a.Name,
|
||||
Created: a.CreatedUnix.AsTime(),
|
||||
DownloadCount: a.DownloadCount,
|
||||
Size: a.Size,
|
||||
UUID: a.UUID,
|
||||
DownloadURL: a.DownloadURL(),
|
||||
}
|
||||
}
|
||||
|
||||
func ToAttachments(attachments []*repo_model.Attachment) []*api.Attachment {
|
||||
converted := make([]*api.Attachment, 0, len(attachments))
|
||||
for _, attachment := range attachments {
|
||||
converted = append(converted, ToAttachment(attachment))
|
||||
}
|
||||
return converted
|
||||
}
|
||||
@@ -1,458 +0,0 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
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"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
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/models/webhook"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
webhook_service "code.gitea.io/gitea/services/webhook"
|
||||
)
|
||||
|
||||
// ToEmail convert models.EmailAddress to api.Email
|
||||
func ToEmail(email *user_model.EmailAddress) *api.Email {
|
||||
return &api.Email{
|
||||
Email: email.Email,
|
||||
Verified: email.IsActivated,
|
||||
Primary: email.IsPrimary,
|
||||
}
|
||||
}
|
||||
|
||||
// ToBranch convert a git.Commit and git.Branch to an api.Branch
|
||||
func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *git_model.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*api.Branch, error) {
|
||||
if bp == nil {
|
||||
var hasPerm bool
|
||||
var canPush bool
|
||||
var err error
|
||||
if user != nil {
|
||||
hasPerm, err = access_model.HasAccessUnit(db.DefaultContext, user, repo, unit.TypeCode, perm.AccessModeWrite)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
perms, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canPush = issues_model.CanMaintainerWriteToBranch(perms, b.Name, user)
|
||||
}
|
||||
|
||||
return &api.Branch{
|
||||
Name: b.Name,
|
||||
Commit: ToPayloadCommit(repo, c),
|
||||
Protected: false,
|
||||
RequiredApprovals: 0,
|
||||
EnableStatusCheck: false,
|
||||
StatusCheckContexts: []string{},
|
||||
UserCanPush: canPush,
|
||||
UserCanMerge: hasPerm,
|
||||
}, nil
|
||||
}
|
||||
|
||||
branch := &api.Branch{
|
||||
Name: b.Name,
|
||||
Commit: ToPayloadCommit(repo, c),
|
||||
Protected: true,
|
||||
RequiredApprovals: bp.RequiredApprovals,
|
||||
EnableStatusCheck: bp.EnableStatusCheck,
|
||||
StatusCheckContexts: bp.StatusCheckContexts,
|
||||
}
|
||||
|
||||
if isRepoAdmin {
|
||||
branch.EffectiveBranchProtectionName = bp.BranchName
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
permission, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
branch.UserCanPush = bp.CanUserPush(user.ID)
|
||||
branch.UserCanMerge = git_model.IsUserMergeWhitelisted(db.DefaultContext, bp, user.ID, permission)
|
||||
}
|
||||
|
||||
return branch, nil
|
||||
}
|
||||
|
||||
// ToBranchProtection convert a ProtectedBranch to api.BranchProtection
|
||||
func ToBranchProtection(bp *git_model.ProtectedBranch) *api.BranchProtection {
|
||||
pushWhitelistUsernames, err := user_model.GetUserNamesByIDs(bp.WhitelistUserIDs)
|
||||
if err != nil {
|
||||
log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err)
|
||||
}
|
||||
mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(bp.MergeWhitelistUserIDs)
|
||||
if err != nil {
|
||||
log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err)
|
||||
}
|
||||
approvalsWhitelistUsernames, err := user_model.GetUserNamesByIDs(bp.ApprovalsWhitelistUserIDs)
|
||||
if err != nil {
|
||||
log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err)
|
||||
}
|
||||
pushWhitelistTeams, err := organization.GetTeamNamesByID(bp.WhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
|
||||
}
|
||||
mergeWhitelistTeams, err := organization.GetTeamNamesByID(bp.MergeWhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
|
||||
}
|
||||
approvalsWhitelistTeams, err := organization.GetTeamNamesByID(bp.ApprovalsWhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err)
|
||||
}
|
||||
|
||||
return &api.BranchProtection{
|
||||
BranchName: bp.BranchName,
|
||||
EnablePush: bp.CanPush,
|
||||
EnablePushWhitelist: bp.EnableWhitelist,
|
||||
PushWhitelistUsernames: pushWhitelistUsernames,
|
||||
PushWhitelistTeams: pushWhitelistTeams,
|
||||
PushWhitelistDeployKeys: bp.WhitelistDeployKeys,
|
||||
EnableMergeWhitelist: bp.EnableMergeWhitelist,
|
||||
MergeWhitelistUsernames: mergeWhitelistUsernames,
|
||||
MergeWhitelistTeams: mergeWhitelistTeams,
|
||||
EnableStatusCheck: bp.EnableStatusCheck,
|
||||
StatusCheckContexts: bp.StatusCheckContexts,
|
||||
RequiredApprovals: bp.RequiredApprovals,
|
||||
EnableApprovalsWhitelist: bp.EnableApprovalsWhitelist,
|
||||
ApprovalsWhitelistUsernames: approvalsWhitelistUsernames,
|
||||
ApprovalsWhitelistTeams: approvalsWhitelistTeams,
|
||||
BlockOnRejectedReviews: bp.BlockOnRejectedReviews,
|
||||
BlockOnOfficialReviewRequests: bp.BlockOnOfficialReviewRequests,
|
||||
BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch,
|
||||
DismissStaleApprovals: bp.DismissStaleApprovals,
|
||||
RequireSignedCommits: bp.RequireSignedCommits,
|
||||
ProtectedFilePatterns: bp.ProtectedFilePatterns,
|
||||
UnprotectedFilePatterns: bp.UnprotectedFilePatterns,
|
||||
Created: bp.CreatedUnix.AsTime(),
|
||||
Updated: bp.UpdatedUnix.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
// ToTag convert a git.Tag to an api.Tag
|
||||
func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
||||
// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
|
||||
func ToVerification(c *git.Commit) *api.PayloadCommitVerification {
|
||||
verif := asymkey_model.ParseCommitWithSignature(c)
|
||||
commitVerification := &api.PayloadCommitVerification{
|
||||
Verified: verif.Verified,
|
||||
Reason: verif.Reason,
|
||||
}
|
||||
if c.Signature != nil {
|
||||
commitVerification.Signature = c.Signature.Signature
|
||||
commitVerification.Payload = c.Signature.Payload
|
||||
}
|
||||
if verif.SigningUser != nil {
|
||||
commitVerification.Signer = &api.PayloadUser{
|
||||
Name: verif.SigningUser.Name,
|
||||
Email: verif.SigningUser.Email,
|
||||
}
|
||||
}
|
||||
return commitVerification
|
||||
}
|
||||
|
||||
// ToPublicKey convert asymkey_model.PublicKey to api.PublicKey
|
||||
func ToPublicKey(apiLink string, key *asymkey_model.PublicKey) *api.PublicKey {
|
||||
return &api.PublicKey{
|
||||
ID: key.ID,
|
||||
Key: key.Content,
|
||||
URL: fmt.Sprintf("%s%d", apiLink, key.ID),
|
||||
Title: key.Name,
|
||||
Fingerprint: key.Fingerprint,
|
||||
Created: key.CreatedUnix.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
// ToGPGKey converts models.GPGKey to api.GPGKey
|
||||
func ToGPGKey(key *asymkey_model.GPGKey) *api.GPGKey {
|
||||
subkeys := make([]*api.GPGKey, len(key.SubsKey))
|
||||
for id, k := range key.SubsKey {
|
||||
subkeys[id] = &api.GPGKey{
|
||||
ID: k.ID,
|
||||
PrimaryKeyID: k.PrimaryKeyID,
|
||||
KeyID: k.KeyID,
|
||||
PublicKey: k.Content,
|
||||
Created: k.CreatedUnix.AsTime(),
|
||||
Expires: k.ExpiredUnix.AsTime(),
|
||||
CanSign: k.CanSign,
|
||||
CanEncryptComms: k.CanEncryptComms,
|
||||
CanEncryptStorage: k.CanEncryptStorage,
|
||||
CanCertify: k.CanSign,
|
||||
Verified: k.Verified,
|
||||
}
|
||||
}
|
||||
emails := make([]*api.GPGKeyEmail, len(key.Emails))
|
||||
for i, e := range key.Emails {
|
||||
emails[i] = ToGPGKeyEmail(e)
|
||||
}
|
||||
return &api.GPGKey{
|
||||
ID: key.ID,
|
||||
PrimaryKeyID: key.PrimaryKeyID,
|
||||
KeyID: key.KeyID,
|
||||
PublicKey: key.Content,
|
||||
Created: key.CreatedUnix.AsTime(),
|
||||
Expires: key.ExpiredUnix.AsTime(),
|
||||
Emails: emails,
|
||||
SubsKey: subkeys,
|
||||
CanSign: key.CanSign,
|
||||
CanEncryptComms: key.CanEncryptComms,
|
||||
CanEncryptStorage: key.CanEncryptStorage,
|
||||
CanCertify: key.CanSign,
|
||||
Verified: key.Verified,
|
||||
}
|
||||
}
|
||||
|
||||
// ToGPGKeyEmail convert models.EmailAddress to api.GPGKeyEmail
|
||||
func ToGPGKeyEmail(email *user_model.EmailAddress) *api.GPGKeyEmail {
|
||||
return &api.GPGKeyEmail{
|
||||
Email: email.Email,
|
||||
Verified: email.IsActivated,
|
||||
}
|
||||
}
|
||||
|
||||
// ToHook convert models.Webhook to api.Hook
|
||||
func ToHook(repoLink string, w *webhook.Webhook) (*api.Hook, error) {
|
||||
config := map[string]string{
|
||||
"url": w.URL,
|
||||
"content_type": w.ContentType.Name(),
|
||||
}
|
||||
if w.Type == webhook.SLACK {
|
||||
s := webhook_service.GetSlackHook(w)
|
||||
config["channel"] = s.Channel
|
||||
config["username"] = s.Username
|
||||
config["icon_url"] = s.IconURL
|
||||
config["color"] = s.Color
|
||||
}
|
||||
|
||||
authorizationHeader, err := w.HeaderAuthorization()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.Hook{
|
||||
ID: w.ID,
|
||||
Type: w.Type,
|
||||
URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID),
|
||||
Active: w.IsActive,
|
||||
Config: config,
|
||||
Events: w.EventsArray(),
|
||||
AuthorizationHeader: authorizationHeader,
|
||||
Updated: w.UpdatedUnix.AsTime(),
|
||||
Created: w.CreatedUnix.AsTime(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToGitHook convert git.Hook to api.GitHook
|
||||
func ToGitHook(h *git.Hook) *api.GitHook {
|
||||
return &api.GitHook{
|
||||
Name: h.Name(),
|
||||
IsActive: h.IsActive,
|
||||
Content: h.Content,
|
||||
}
|
||||
}
|
||||
|
||||
// ToDeployKey convert asymkey_model.DeployKey to api.DeployKey
|
||||
func ToDeployKey(apiLink string, key *asymkey_model.DeployKey) *api.DeployKey {
|
||||
return &api.DeployKey{
|
||||
ID: key.ID,
|
||||
KeyID: key.KeyID,
|
||||
Key: key.Content,
|
||||
Fingerprint: key.Fingerprint,
|
||||
URL: fmt.Sprintf("%s%d", apiLink, key.ID),
|
||||
Title: key.Name,
|
||||
Created: key.CreatedUnix.AsTime(),
|
||||
ReadOnly: key.Mode == perm.AccessModeRead, // All deploy keys are read-only.
|
||||
}
|
||||
}
|
||||
|
||||
// ToOrganization convert user_model.User to api.Organization
|
||||
func ToOrganization(org *organization.Organization) *api.Organization {
|
||||
return &api.Organization{
|
||||
ID: org.ID,
|
||||
AvatarURL: org.AsUser().AvatarLink(),
|
||||
Name: org.Name,
|
||||
UserName: org.Name,
|
||||
FullName: org.FullName,
|
||||
Description: org.Description,
|
||||
Website: org.Website,
|
||||
Location: org.Location,
|
||||
Visibility: org.Visibility.String(),
|
||||
RepoAdminChangeTeamAccess: org.RepoAdminChangeTeamAccess,
|
||||
}
|
||||
}
|
||||
|
||||
// ToTeam convert models.Team to api.Team
|
||||
func ToTeam(team *organization.Team, loadOrg ...bool) (*api.Team, error) {
|
||||
teams, err := ToTeams([]*organization.Team{team}, len(loadOrg) != 0 && loadOrg[0])
|
||||
if err != nil || len(teams) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return teams[0], nil
|
||||
}
|
||||
|
||||
// ToTeams convert models.Team list to api.Team list
|
||||
func ToTeams(teams []*organization.Team, loadOrgs bool) ([]*api.Team, error) {
|
||||
if len(teams) == 0 || teams[0] == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cache := make(map[int64]*api.Organization)
|
||||
apiTeams := make([]*api.Team, len(teams))
|
||||
for i := range teams {
|
||||
if err := teams[i].GetUnits(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiTeams[i] = &api.Team{
|
||||
ID: teams[i].ID,
|
||||
Name: teams[i].Name,
|
||||
Description: teams[i].Description,
|
||||
IncludesAllRepositories: teams[i].IncludesAllRepositories,
|
||||
CanCreateOrgRepo: teams[i].CanCreateOrgRepo,
|
||||
Permission: teams[i].AccessMode.String(),
|
||||
Units: teams[i].GetUnitNames(),
|
||||
UnitsMap: teams[i].GetUnitsMap(),
|
||||
}
|
||||
|
||||
if loadOrgs {
|
||||
apiOrg, ok := cache[teams[i].OrgID]
|
||||
if !ok {
|
||||
org, err := organization.GetOrgByID(db.DefaultContext, teams[i].OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apiOrg = ToOrganization(org)
|
||||
cache[teams[i].OrgID] = apiOrg
|
||||
}
|
||||
apiTeams[i].Organization = apiOrg
|
||||
}
|
||||
}
|
||||
return apiTeams, nil
|
||||
}
|
||||
|
||||
// ToAnnotatedTag convert git.Tag to api.AnnotatedTag
|
||||
func ToAnnotatedTag(repo *repo_model.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
|
||||
return &api.AnnotatedTag{
|
||||
Tag: t.Name,
|
||||
SHA: t.ID.String(),
|
||||
Object: ToAnnotatedTagObject(repo, c),
|
||||
Message: t.Message,
|
||||
URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()),
|
||||
Tagger: ToCommitUser(t.Tagger),
|
||||
Verification: ToVerification(c),
|
||||
}
|
||||
}
|
||||
|
||||
// ToAnnotatedTagObject convert a git.Commit to an api.AnnotatedTagObject
|
||||
func ToAnnotatedTagObject(repo *repo_model.Repository, commit *git.Commit) *api.AnnotatedTagObject {
|
||||
return &api.AnnotatedTagObject{
|
||||
SHA: commit.ID.String(),
|
||||
Type: string(git.ObjectCommit),
|
||||
URL: util.URLJoin(repo.APIURL(), "git/commits", commit.ID.String()),
|
||||
}
|
||||
}
|
||||
|
||||
// ToTopicResponse convert from models.Topic to api.TopicResponse
|
||||
func ToTopicResponse(topic *repo_model.Topic) *api.TopicResponse {
|
||||
return &api.TopicResponse{
|
||||
ID: topic.ID,
|
||||
Name: topic.Name,
|
||||
RepoCount: topic.RepoCount,
|
||||
Created: topic.CreatedUnix.AsTime(),
|
||||
Updated: topic.UpdatedUnix.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
// ToOAuth2Application convert from auth.OAuth2Application to api.OAuth2Application
|
||||
func ToOAuth2Application(app *auth.OAuth2Application) *api.OAuth2Application {
|
||||
return &api.OAuth2Application{
|
||||
ID: app.ID,
|
||||
Name: app.Name,
|
||||
ClientID: app.ClientID,
|
||||
ClientSecret: app.ClientSecret,
|
||||
ConfidentialClient: app.ConfidentialClient,
|
||||
RedirectURIs: app.RedirectURIs,
|
||||
Created: app.CreatedUnix.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
// ToLFSLock convert a LFSLock to api.LFSLock
|
||||
func ToLFSLock(ctx context.Context, l *git_model.LFSLock) *api.LFSLock {
|
||||
u, err := user_model.GetUserByID(ctx, l.OwnerID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &api.LFSLock{
|
||||
ID: strconv.FormatInt(l.ID, 10),
|
||||
Path: l.Path,
|
||||
LockedAt: l.Created.Round(time.Second),
|
||||
Owner: &api.LFSLockOwner{
|
||||
Name: u.Name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ToChangedFile convert a gitdiff.DiffFile to api.ChangedFile
|
||||
func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile {
|
||||
status := "changed"
|
||||
if f.IsDeleted {
|
||||
status = "deleted"
|
||||
} else if f.IsCreated {
|
||||
status = "added"
|
||||
} else if f.IsRenamed && f.Type == gitdiff.DiffFileCopy {
|
||||
status = "copied"
|
||||
} else if f.IsRenamed && f.Type == gitdiff.DiffFileRename {
|
||||
status = "renamed"
|
||||
} else if f.Addition == 0 && f.Deletion == 0 {
|
||||
status = "unchanged"
|
||||
}
|
||||
|
||||
file := &api.ChangedFile{
|
||||
Filename: f.GetDiffFileName(),
|
||||
Status: status,
|
||||
Additions: f.Addition,
|
||||
Deletions: f.Deletion,
|
||||
Changes: f.Addition + f.Deletion,
|
||||
HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
|
||||
ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
|
||||
RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
|
||||
}
|
||||
|
||||
if status == "rename" {
|
||||
file.PreviousFilename = f.OldName
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
// ToCommitUser convert a git.Signature to an api.CommitUser
|
||||
func ToCommitUser(sig *git.Signature) *api.CommitUser {
|
||||
return &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: sig.Name,
|
||||
Email: sig.Email,
|
||||
},
|
||||
Date: sig.When.UTC().Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
// ToCommitMeta convert a git.Tag to an api.CommitMeta
|
||||
func ToCommitMeta(repo *repo_model.Repository, tag *git.Tag) *api.CommitMeta {
|
||||
return &api.CommitMeta{
|
||||
SHA: tag.Object.String(),
|
||||
URL: util.URLJoin(repo.APIURL(), "git/commits", tag.ID.String()),
|
||||
Created: tag.Tagger.When,
|
||||
}
|
||||
}
|
||||
|
||||
// ToPayloadCommit convert a git.Commit to api.PayloadCommit
|
||||
func ToPayloadCommit(repo *repo_model.Repository, c *git.Commit) *api.PayloadCommit {
|
||||
authorUsername := ""
|
||||
if author, err := user_model.GetUserByEmail(c.Author.Email); err == nil {
|
||||
authorUsername = author.Name
|
||||
} else if !user_model.IsErrUserNotExist(err) {
|
||||
log.Error("GetUserByEmail: %v", err)
|
||||
}
|
||||
|
||||
committerUsername := ""
|
||||
if committer, err := user_model.GetUserByEmail(c.Committer.Email); err == nil {
|
||||
committerUsername = committer.Name
|
||||
} else if !user_model.IsErrUserNotExist(err) {
|
||||
log.Error("GetUserByEmail: %v", err)
|
||||
}
|
||||
|
||||
return &api.PayloadCommit{
|
||||
ID: c.ID.String(),
|
||||
Message: c.Message(),
|
||||
URL: util.URLJoin(repo.HTMLURL(), "commit", c.ID.String()),
|
||||
Author: &api.PayloadUser{
|
||||
Name: c.Author.Name,
|
||||
Email: c.Author.Email,
|
||||
UserName: authorUsername,
|
||||
},
|
||||
Committer: &api.PayloadUser{
|
||||
Name: c.Committer.Name,
|
||||
Email: c.Committer.Email,
|
||||
UserName: committerUsername,
|
||||
},
|
||||
Timestamp: c.Author.When,
|
||||
Verification: ToVerification(c),
|
||||
}
|
||||
}
|
||||
|
||||
// ToCommit convert a git.Commit to api.Commit
|
||||
func ToCommit(repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, stat bool) (*api.Commit, error) {
|
||||
var apiAuthor, apiCommitter *api.User
|
||||
|
||||
// Retrieve author and committer information
|
||||
|
||||
var cacheAuthor *user_model.User
|
||||
var ok bool
|
||||
if userCache == nil {
|
||||
cacheAuthor = (*user_model.User)(nil)
|
||||
ok = false
|
||||
} else {
|
||||
cacheAuthor, ok = userCache[commit.Author.Email]
|
||||
}
|
||||
|
||||
if ok {
|
||||
apiAuthor = ToUser(cacheAuthor, nil)
|
||||
} else {
|
||||
author, err := user_model.GetUserByEmail(commit.Author.Email)
|
||||
if err != nil && !user_model.IsErrUserNotExist(err) {
|
||||
return nil, err
|
||||
} else if err == nil {
|
||||
apiAuthor = ToUser(author, nil)
|
||||
if userCache != nil {
|
||||
userCache[commit.Author.Email] = author
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cacheCommitter *user_model.User
|
||||
if userCache == nil {
|
||||
cacheCommitter = (*user_model.User)(nil)
|
||||
ok = false
|
||||
} else {
|
||||
cacheCommitter, ok = userCache[commit.Committer.Email]
|
||||
}
|
||||
|
||||
if ok {
|
||||
apiCommitter = ToUser(cacheCommitter, nil)
|
||||
} else {
|
||||
committer, err := user_model.GetUserByEmail(commit.Committer.Email)
|
||||
if err != nil && !user_model.IsErrUserNotExist(err) {
|
||||
return nil, err
|
||||
} else if err == nil {
|
||||
apiCommitter = ToUser(committer, nil)
|
||||
if userCache != nil {
|
||||
userCache[commit.Committer.Email] = committer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve parent(s) of the commit
|
||||
apiParents := make([]*api.CommitMeta, commit.ParentCount())
|
||||
for i := 0; i < commit.ParentCount(); i++ {
|
||||
sha, _ := commit.ParentID(i)
|
||||
apiParents[i] = &api.CommitMeta{
|
||||
URL: repo.APIURL() + "/git/commits/" + url.PathEscape(sha.String()),
|
||||
SHA: sha.String(),
|
||||
}
|
||||
}
|
||||
|
||||
res := &api.Commit{
|
||||
CommitMeta: &api.CommitMeta{
|
||||
URL: repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()),
|
||||
SHA: commit.ID.String(),
|
||||
Created: commit.Committer.When,
|
||||
},
|
||||
HTMLURL: repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()),
|
||||
RepoCommit: &api.RepoCommit{
|
||||
URL: repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()),
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
},
|
||||
Date: commit.Author.When.Format(time.RFC3339),
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: commit.Committer.Name,
|
||||
Email: commit.Committer.Email,
|
||||
},
|
||||
Date: commit.Committer.When.Format(time.RFC3339),
|
||||
},
|
||||
Message: commit.Message(),
|
||||
Tree: &api.CommitMeta{
|
||||
URL: repo.APIURL() + "/git/trees/" + url.PathEscape(commit.ID.String()),
|
||||
SHA: commit.ID.String(),
|
||||
Created: commit.Committer.When,
|
||||
},
|
||||
Verification: ToVerification(commit),
|
||||
},
|
||||
Author: apiAuthor,
|
||||
Committer: apiCommitter,
|
||||
Parents: apiParents,
|
||||
}
|
||||
|
||||
// Retrieve files affected by the commit
|
||||
if stat {
|
||||
fileStatus, err := git.GetCommitFileStatus(gitRepo.Ctx, repo.RepoPath(), commit.ID.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
affectedFileList := make([]*api.CommitAffectedFiles, 0, len(fileStatus.Added)+len(fileStatus.Removed)+len(fileStatus.Modified))
|
||||
for _, files := range [][]string{fileStatus.Added, fileStatus.Removed, fileStatus.Modified} {
|
||||
for _, filename := range files {
|
||||
affectedFileList = append(affectedFileList, &api.CommitAffectedFiles{
|
||||
Filename: filename,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
AfterCommitID: commit.ID.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.Files = affectedFileList
|
||||
res.Stats = &api.CommitStats{
|
||||
Total: diff.TotalAddition + diff.TotalDeletion,
|
||||
Additions: diff.TotalAddition,
|
||||
Deletions: diff.TotalDeletion,
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToCommitMeta(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
sha1, _ := git.NewIDFromString("0000000000000000000000000000000000000000")
|
||||
signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)}
|
||||
tag := &git.Tag{
|
||||
Name: "Test Tag",
|
||||
ID: sha1,
|
||||
Object: sha1,
|
||||
Type: "Test Type",
|
||||
Tagger: signature,
|
||||
Message: "Test Message",
|
||||
}
|
||||
|
||||
commitMeta := ToCommitMeta(headRepo, tag)
|
||||
|
||||
assert.NotNil(t, commitMeta)
|
||||
assert.EqualValues(t, &api.CommitMeta{
|
||||
SHA: "0000000000000000000000000000000000000000",
|
||||
URL: util.URLJoin(headRepo.APIURL(), "git/commits", "0000000000000000000000000000000000000000"),
|
||||
Created: time.Unix(0, 0),
|
||||
}, commitMeta)
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToAPIIssue converts an Issue to API format
|
||||
// it assumes some fields assigned with values:
|
||||
// Required - Poster, Labels,
|
||||
// Optional - Milestone, Assignee, PullRequest
|
||||
func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
|
||||
if err := issue.LoadLabels(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
if err := issue.LoadPoster(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
if err := issue.Repo.GetOwner(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
|
||||
apiIssue := &api.Issue{
|
||||
ID: issue.ID,
|
||||
URL: issue.APIURL(),
|
||||
HTMLURL: issue.HTMLURL(),
|
||||
Index: issue.Index,
|
||||
Poster: ToUser(issue.Poster, nil),
|
||||
Title: issue.Title,
|
||||
Body: issue.Content,
|
||||
Attachments: ToAttachments(issue.Attachments),
|
||||
Ref: issue.Ref,
|
||||
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
|
||||
State: issue.State(),
|
||||
IsLocked: issue.IsLocked,
|
||||
Comments: issue.NumComments,
|
||||
Created: issue.CreatedUnix.AsTime(),
|
||||
Updated: issue.UpdatedUnix.AsTime(),
|
||||
}
|
||||
|
||||
apiIssue.Repo = &api.RepositoryMeta{
|
||||
ID: issue.Repo.ID,
|
||||
Name: issue.Repo.Name,
|
||||
Owner: issue.Repo.OwnerName,
|
||||
FullName: issue.Repo.FullName(),
|
||||
}
|
||||
|
||||
if issue.ClosedUnix != 0 {
|
||||
apiIssue.Closed = issue.ClosedUnix.AsTimePtr()
|
||||
}
|
||||
|
||||
if err := issue.LoadMilestone(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
if issue.Milestone != nil {
|
||||
apiIssue.Milestone = ToAPIMilestone(issue.Milestone)
|
||||
}
|
||||
|
||||
if err := issue.LoadAssignees(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
if len(issue.Assignees) > 0 {
|
||||
for _, assignee := range issue.Assignees {
|
||||
apiIssue.Assignees = append(apiIssue.Assignees, ToUser(assignee, nil))
|
||||
}
|
||||
apiIssue.Assignee = ToUser(issue.Assignees[0], nil) // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
|
||||
}
|
||||
if issue.IsPull {
|
||||
if err := issue.LoadPullRequest(ctx); err != nil {
|
||||
return &api.Issue{}
|
||||
}
|
||||
apiIssue.PullRequest = &api.PullRequestMeta{
|
||||
HasMerged: issue.PullRequest.HasMerged,
|
||||
}
|
||||
if issue.PullRequest.HasMerged {
|
||||
apiIssue.PullRequest.Merged = issue.PullRequest.MergedUnix.AsTimePtr()
|
||||
}
|
||||
}
|
||||
if issue.DeadlineUnix != 0 {
|
||||
apiIssue.Deadline = issue.DeadlineUnix.AsTimePtr()
|
||||
}
|
||||
|
||||
return apiIssue
|
||||
}
|
||||
|
||||
// ToAPIIssueList converts an IssueList to API format
|
||||
func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue {
|
||||
result := make([]*api.Issue, len(il))
|
||||
for i := range il {
|
||||
result[i] = ToAPIIssue(ctx, il[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ToTrackedTime converts TrackedTime to API format
|
||||
func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) {
|
||||
apiT = &api.TrackedTime{
|
||||
ID: t.ID,
|
||||
IssueID: t.IssueID,
|
||||
UserID: t.UserID,
|
||||
Time: t.Time,
|
||||
Created: t.Created,
|
||||
}
|
||||
if t.Issue != nil {
|
||||
apiT.Issue = ToAPIIssue(ctx, t.Issue)
|
||||
}
|
||||
if t.User != nil {
|
||||
apiT.UserName = t.User.Name
|
||||
}
|
||||
return apiT
|
||||
}
|
||||
|
||||
// ToStopWatches convert Stopwatch list to api.StopWatches
|
||||
func ToStopWatches(sws []*issues_model.Stopwatch) (api.StopWatches, error) {
|
||||
result := api.StopWatches(make([]api.StopWatch, 0, len(sws)))
|
||||
|
||||
issueCache := make(map[int64]*issues_model.Issue)
|
||||
repoCache := make(map[int64]*repo_model.Repository)
|
||||
var (
|
||||
issue *issues_model.Issue
|
||||
repo *repo_model.Repository
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
|
||||
for _, sw := range sws {
|
||||
issue, ok = issueCache[sw.IssueID]
|
||||
if !ok {
|
||||
issue, err = issues_model.GetIssueByID(db.DefaultContext, sw.IssueID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
repo, ok = repoCache[issue.RepoID]
|
||||
if !ok {
|
||||
repo, err = repo_model.GetRepositoryByID(db.DefaultContext, issue.RepoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, api.StopWatch{
|
||||
Created: sw.CreatedUnix.AsTime(),
|
||||
Seconds: sw.Seconds(),
|
||||
Duration: sw.Duration(),
|
||||
IssueIndex: issue.Index,
|
||||
IssueTitle: issue.Title,
|
||||
RepoOwnerName: repo.OwnerName,
|
||||
RepoName: repo.Name,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ToTrackedTimeList converts TrackedTimeList to API format
|
||||
func ToTrackedTimeList(ctx context.Context, tl issues_model.TrackedTimeList) api.TrackedTimeList {
|
||||
result := make([]*api.TrackedTime, 0, len(tl))
|
||||
for _, t := range tl {
|
||||
result = append(result, ToTrackedTime(ctx, t))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ToLabel converts Label to API format
|
||||
func ToLabel(label *issues_model.Label, repo *repo_model.Repository, org *user_model.User) *api.Label {
|
||||
result := &api.Label{
|
||||
ID: label.ID,
|
||||
Name: label.Name,
|
||||
Color: strings.TrimLeft(label.Color, "#"),
|
||||
Description: label.Description,
|
||||
}
|
||||
|
||||
// calculate URL
|
||||
if label.BelongsToRepo() && repo != nil {
|
||||
if repo != nil {
|
||||
result.URL = fmt.Sprintf("%s/labels/%d", repo.APIURL(), label.ID)
|
||||
} else {
|
||||
log.Error("ToLabel did not get repo to calculate url for label with id '%d'", label.ID)
|
||||
}
|
||||
} else { // BelongsToOrg
|
||||
if org != nil {
|
||||
result.URL = fmt.Sprintf("%sapi/v1/orgs/%s/labels/%d", setting.AppURL, url.PathEscape(org.Name), label.ID)
|
||||
} else {
|
||||
log.Error("ToLabel did not get org to calculate url for label with id '%d'", label.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ToLabelList converts list of Label to API format
|
||||
func ToLabelList(labels []*issues_model.Label, repo *repo_model.Repository, org *user_model.User) []*api.Label {
|
||||
result := make([]*api.Label, len(labels))
|
||||
for i := range labels {
|
||||
result[i] = ToLabel(labels[i], repo, org)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ToAPIMilestone converts Milestone into API Format
|
||||
func ToAPIMilestone(m *issues_model.Milestone) *api.Milestone {
|
||||
apiMilestone := &api.Milestone{
|
||||
ID: m.ID,
|
||||
State: m.State(),
|
||||
Title: m.Name,
|
||||
Description: m.Content,
|
||||
OpenIssues: m.NumOpenIssues,
|
||||
ClosedIssues: m.NumClosedIssues,
|
||||
Created: m.CreatedUnix.AsTime(),
|
||||
Updated: m.UpdatedUnix.AsTimePtr(),
|
||||
}
|
||||
if m.IsClosed {
|
||||
apiMilestone.Closed = m.ClosedDateUnix.AsTimePtr()
|
||||
}
|
||||
if m.DeadlineUnix.Year() < 9999 {
|
||||
apiMilestone.Deadline = m.DeadlineUnix.AsTimePtr()
|
||||
}
|
||||
return apiMilestone
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToComment converts a issues_model.Comment to the api.Comment format
|
||||
func ToComment(c *issues_model.Comment) *api.Comment {
|
||||
return &api.Comment{
|
||||
ID: c.ID,
|
||||
Poster: ToUser(c.Poster, nil),
|
||||
HTMLURL: c.HTMLURL(),
|
||||
IssueURL: c.IssueURL(),
|
||||
PRURL: c.PRURL(),
|
||||
Body: c.Content,
|
||||
Attachments: ToAttachments(c.Attachments),
|
||||
Created: c.CreatedUnix.AsTime(),
|
||||
Updated: c.UpdatedUnix.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
// ToTimelineComment converts a issues_model.Comment to the api.TimelineComment format
|
||||
func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_model.User) *api.TimelineComment {
|
||||
err := c.LoadMilestone(ctx)
|
||||
if err != nil {
|
||||
log.Error("LoadMilestone: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = c.LoadAssigneeUserAndTeam()
|
||||
if err != nil {
|
||||
log.Error("LoadAssigneeUserAndTeam: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = c.LoadResolveDoer()
|
||||
if err != nil {
|
||||
log.Error("LoadResolveDoer: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = c.LoadDepIssueDetails()
|
||||
if err != nil {
|
||||
log.Error("LoadDepIssueDetails: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = c.LoadTime()
|
||||
if err != nil {
|
||||
log.Error("LoadTime: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = c.LoadLabel()
|
||||
if err != nil {
|
||||
log.Error("LoadLabel: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
comment := &api.TimelineComment{
|
||||
ID: c.ID,
|
||||
Type: c.Type.String(),
|
||||
Poster: ToUser(c.Poster, nil),
|
||||
HTMLURL: c.HTMLURL(),
|
||||
IssueURL: c.IssueURL(),
|
||||
PRURL: c.PRURL(),
|
||||
Body: c.Content,
|
||||
Created: c.CreatedUnix.AsTime(),
|
||||
Updated: c.UpdatedUnix.AsTime(),
|
||||
|
||||
OldProjectID: c.OldProjectID,
|
||||
ProjectID: c.ProjectID,
|
||||
|
||||
OldTitle: c.OldTitle,
|
||||
NewTitle: c.NewTitle,
|
||||
|
||||
OldRef: c.OldRef,
|
||||
NewRef: c.NewRef,
|
||||
|
||||
RefAction: c.RefAction.String(),
|
||||
RefCommitSHA: c.CommitSHA,
|
||||
|
||||
ReviewID: c.ReviewID,
|
||||
|
||||
RemovedAssignee: c.RemovedAssignee,
|
||||
}
|
||||
|
||||
if c.OldMilestone != nil {
|
||||
comment.OldMilestone = ToAPIMilestone(c.OldMilestone)
|
||||
}
|
||||
if c.Milestone != nil {
|
||||
comment.Milestone = ToAPIMilestone(c.Milestone)
|
||||
}
|
||||
|
||||
if c.Time != nil {
|
||||
err = c.Time.LoadAttributes()
|
||||
if err != nil {
|
||||
log.Error("Time.LoadAttributes: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
comment.TrackedTime = ToTrackedTime(ctx, c.Time)
|
||||
}
|
||||
|
||||
if c.RefIssueID != 0 {
|
||||
issue, err := issues_model.GetIssueByID(ctx, c.RefIssueID)
|
||||
if err != nil {
|
||||
log.Error("GetIssueByID(%d): %v", c.RefIssueID, err)
|
||||
return nil
|
||||
}
|
||||
comment.RefIssue = ToAPIIssue(ctx, issue)
|
||||
}
|
||||
|
||||
if c.RefCommentID != 0 {
|
||||
com, err := issues_model.GetCommentByID(ctx, c.RefCommentID)
|
||||
if err != nil {
|
||||
log.Error("GetCommentByID(%d): %v", c.RefCommentID, err)
|
||||
return nil
|
||||
}
|
||||
err = com.LoadPoster(ctx)
|
||||
if err != nil {
|
||||
log.Error("LoadPoster: %v", err)
|
||||
return nil
|
||||
}
|
||||
comment.RefComment = ToComment(com)
|
||||
}
|
||||
|
||||
if c.Label != nil {
|
||||
var org *user_model.User
|
||||
var repo *repo_model.Repository
|
||||
if c.Label.BelongsToOrg() {
|
||||
var err error
|
||||
org, err = user_model.GetUserByID(ctx, c.Label.OrgID)
|
||||
if err != nil {
|
||||
log.Error("GetUserByID(%d): %v", c.Label.OrgID, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if c.Label.BelongsToRepo() {
|
||||
var err error
|
||||
repo, err = repo_model.GetRepositoryByID(ctx, c.Label.RepoID)
|
||||
if err != nil {
|
||||
log.Error("GetRepositoryByID(%d): %v", c.Label.RepoID, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
comment.Label = ToLabel(c.Label, repo, org)
|
||||
}
|
||||
|
||||
if c.Assignee != nil {
|
||||
comment.Assignee = ToUser(c.Assignee, nil)
|
||||
}
|
||||
if c.AssigneeTeam != nil {
|
||||
comment.AssigneeTeam, _ = ToTeam(c.AssigneeTeam)
|
||||
}
|
||||
|
||||
if c.ResolveDoer != nil {
|
||||
comment.ResolveDoer = ToUser(c.ResolveDoer, nil)
|
||||
}
|
||||
|
||||
if c.DependentIssue != nil {
|
||||
comment.DependentIssue = ToAPIIssue(ctx, c.DependentIssue)
|
||||
}
|
||||
|
||||
return comment
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLabel_ToLabel(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: label.RepoID})
|
||||
assert.Equal(t, &api.Label{
|
||||
ID: label.ID,
|
||||
Name: label.Name,
|
||||
Color: "abcdef",
|
||||
URL: fmt.Sprintf("%sapi/v1/repos/user2/repo1/labels/%d", setting.AppURL, label.ID),
|
||||
}, ToLabel(label, repo, nil))
|
||||
}
|
||||
|
||||
func TestMilestone_APIFormat(t *testing.T) {
|
||||
milestone := &issues_model.Milestone{
|
||||
ID: 3,
|
||||
RepoID: 4,
|
||||
Name: "milestoneName",
|
||||
Content: "milestoneContent",
|
||||
IsClosed: false,
|
||||
NumOpenIssues: 5,
|
||||
NumClosedIssues: 6,
|
||||
CreatedUnix: timeutil.TimeStamp(time.Date(1999, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()),
|
||||
UpdatedUnix: timeutil.TimeStamp(time.Date(1999, time.March, 1, 0, 0, 0, 0, time.UTC).Unix()),
|
||||
DeadlineUnix: timeutil.TimeStamp(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()),
|
||||
}
|
||||
assert.Equal(t, api.Milestone{
|
||||
ID: milestone.ID,
|
||||
State: api.StateOpen,
|
||||
Title: milestone.Name,
|
||||
Description: milestone.Content,
|
||||
OpenIssues: milestone.NumOpenIssues,
|
||||
ClosedIssues: milestone.NumClosedIssues,
|
||||
Created: milestone.CreatedUnix.AsTime(),
|
||||
Updated: milestone.UpdatedUnix.AsTimePtr(),
|
||||
Deadline: milestone.DeadlineUnix.AsTimePtr(),
|
||||
}, *ToAPIMilestone(milestone))
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToPushMirror convert from repo_model.PushMirror and remoteAddress to api.TopicResponse
|
||||
func ToPushMirror(pm *repo_model.PushMirror) (*api.PushMirror, error) {
|
||||
repo := pm.GetRepository()
|
||||
remoteAddress, err := getRemoteAddress(repo, pm.RemoteName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &api.PushMirror{
|
||||
RepoName: repo.Name,
|
||||
RemoteName: pm.RemoteName,
|
||||
RemoteAddress: remoteAddress,
|
||||
CreatedUnix: pm.CreatedUnix.FormatLong(),
|
||||
LastUpdateUnix: pm.LastUpdateUnix.FormatLong(),
|
||||
LastError: pm.LastError,
|
||||
Interval: pm.Interval.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getRemoteAddress(repo *repo_model.Repository, remoteName string) (string, error) {
|
||||
url, err := git.GetRemoteURL(git.DefaultContext, repo.RepoPath(), remoteName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// remove confidential information
|
||||
url.User = nil
|
||||
return url.String(), nil
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToNotificationThread convert a Notification to api.NotificationThread
|
||||
func ToNotificationThread(n *activities_model.Notification) *api.NotificationThread {
|
||||
result := &api.NotificationThread{
|
||||
ID: n.ID,
|
||||
Unread: !(n.Status == activities_model.NotificationStatusRead || n.Status == activities_model.NotificationStatusPinned),
|
||||
Pinned: n.Status == activities_model.NotificationStatusPinned,
|
||||
UpdatedAt: n.UpdatedUnix.AsTime(),
|
||||
URL: n.APIURL(),
|
||||
}
|
||||
|
||||
// since user only get notifications when he has access to use minimal access mode
|
||||
if n.Repository != nil {
|
||||
result.Repository = ToRepo(db.DefaultContext, n.Repository, perm.AccessModeRead)
|
||||
|
||||
// This permission is not correct and we should not be reporting it
|
||||
for repository := result.Repository; repository != nil; repository = repository.Parent {
|
||||
repository.Permissions = nil
|
||||
}
|
||||
}
|
||||
|
||||
// handle Subject
|
||||
switch n.Source {
|
||||
case activities_model.NotificationSourceIssue:
|
||||
result.Subject = &api.NotificationSubject{Type: api.NotifySubjectIssue}
|
||||
if n.Issue != nil {
|
||||
result.Subject.Title = n.Issue.Title
|
||||
result.Subject.URL = n.Issue.APIURL()
|
||||
result.Subject.HTMLURL = n.Issue.HTMLURL()
|
||||
result.Subject.State = n.Issue.State()
|
||||
comment, err := n.Issue.GetLastComment()
|
||||
if err == nil && comment != nil {
|
||||
result.Subject.LatestCommentURL = comment.APIURL()
|
||||
result.Subject.LatestCommentHTMLURL = comment.HTMLURL()
|
||||
}
|
||||
}
|
||||
case activities_model.NotificationSourcePullRequest:
|
||||
result.Subject = &api.NotificationSubject{Type: api.NotifySubjectPull}
|
||||
if n.Issue != nil {
|
||||
result.Subject.Title = n.Issue.Title
|
||||
result.Subject.URL = n.Issue.APIURL()
|
||||
result.Subject.HTMLURL = n.Issue.HTMLURL()
|
||||
result.Subject.State = n.Issue.State()
|
||||
comment, err := n.Issue.GetLastComment()
|
||||
if err == nil && comment != nil {
|
||||
result.Subject.LatestCommentURL = comment.APIURL()
|
||||
result.Subject.LatestCommentHTMLURL = comment.HTMLURL()
|
||||
}
|
||||
|
||||
pr, _ := n.Issue.GetPullRequest()
|
||||
if pr != nil && pr.HasMerged {
|
||||
result.Subject.State = "merged"
|
||||
}
|
||||
}
|
||||
case activities_model.NotificationSourceCommit:
|
||||
url := n.Repository.HTMLURL() + "/commit/" + url.PathEscape(n.CommitID)
|
||||
result.Subject = &api.NotificationSubject{
|
||||
Type: api.NotifySubjectCommit,
|
||||
Title: n.CommitID,
|
||||
URL: url,
|
||||
HTMLURL: url,
|
||||
}
|
||||
case activities_model.NotificationSourceRepository:
|
||||
result.Subject = &api.NotificationSubject{
|
||||
Type: api.NotifySubjectRepository,
|
||||
Title: n.Repository.FullName(),
|
||||
// FIXME: this is a relative URL, rather useless and inconsistent, but keeping for backwards compat
|
||||
URL: n.Repository.Link(),
|
||||
HTMLURL: n.Repository.HTMLURL(),
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ToNotifications convert list of Notification to api.NotificationThread list
|
||||
func ToNotifications(nl activities_model.NotificationList) []*api.NotificationThread {
|
||||
result := make([]*api.NotificationThread, 0, len(nl))
|
||||
for _, n := range nl {
|
||||
result = append(result, ToNotificationThread(n))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToPackage convert a packages.PackageDescriptor to api.Package
|
||||
func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_model.User) (*api.Package, error) {
|
||||
var repo *api.Repository
|
||||
if pd.Repository != nil {
|
||||
permission, err := access_model.GetUserRepoPermission(ctx, pd.Repository, doer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if permission.HasAccess() {
|
||||
repo = ToRepo(ctx, pd.Repository, permission.AccessMode)
|
||||
}
|
||||
}
|
||||
|
||||
return &api.Package{
|
||||
ID: pd.Version.ID,
|
||||
Owner: ToUser(pd.Owner, doer),
|
||||
Repository: repo,
|
||||
Creator: ToUser(pd.Creator, doer),
|
||||
Type: string(pd.Package.Type),
|
||||
Name: pd.Package.Name,
|
||||
Version: pd.Version.Version,
|
||||
CreatedAt: pd.Version.CreatedUnix.AsTime(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToPackageFile converts packages.PackageFileDescriptor to api.PackageFile
|
||||
func ToPackageFile(pfd *packages.PackageFileDescriptor) *api.PackageFile {
|
||||
return &api.PackageFile{
|
||||
ID: pfd.File.ID,
|
||||
Size: pfd.Blob.Size,
|
||||
Name: pfd.File.Name,
|
||||
HashMD5: pfd.Blob.HashMD5,
|
||||
HashSHA1: pfd.Blob.HashSHA1,
|
||||
HashSHA256: pfd.Blob.HashSHA256,
|
||||
HashSHA512: pfd.Blob.HashSHA512,
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToAPIPullRequest assumes following fields have been assigned with valid values:
|
||||
// Required - Issue
|
||||
// Optional - Merger
|
||||
func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) *api.PullRequest {
|
||||
var (
|
||||
baseBranch *git.Branch
|
||||
headBranch *git.Branch
|
||||
baseCommit *git.Commit
|
||||
err error
|
||||
)
|
||||
|
||||
if err = pr.Issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("pr.Issue.LoadRepo[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
apiIssue := ToAPIIssue(ctx, pr.Issue)
|
||||
if err := pr.LoadBaseRepo(ctx); err != nil {
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := pr.LoadHeadRepo(ctx); err != nil {
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
p, err := access_model.GetUserRepoPermission(ctx, pr.BaseRepo, doer)
|
||||
if err != nil {
|
||||
log.Error("GetUserRepoPermission[%d]: %v", pr.BaseRepoID, err)
|
||||
p.AccessMode = perm.AccessModeNone
|
||||
}
|
||||
|
||||
apiPullRequest := &api.PullRequest{
|
||||
ID: pr.ID,
|
||||
URL: pr.Issue.HTMLURL(),
|
||||
Index: pr.Index,
|
||||
Poster: apiIssue.Poster,
|
||||
Title: apiIssue.Title,
|
||||
Body: apiIssue.Body,
|
||||
Labels: apiIssue.Labels,
|
||||
Milestone: apiIssue.Milestone,
|
||||
Assignee: apiIssue.Assignee,
|
||||
Assignees: apiIssue.Assignees,
|
||||
State: apiIssue.State,
|
||||
IsLocked: apiIssue.IsLocked,
|
||||
Comments: apiIssue.Comments,
|
||||
HTMLURL: pr.Issue.HTMLURL(),
|
||||
DiffURL: pr.Issue.DiffURL(),
|
||||
PatchURL: pr.Issue.PatchURL(),
|
||||
HasMerged: pr.HasMerged,
|
||||
MergeBase: pr.MergeBase,
|
||||
Mergeable: pr.Mergeable(),
|
||||
Deadline: apiIssue.Deadline,
|
||||
Created: pr.Issue.CreatedUnix.AsTimePtr(),
|
||||
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
|
||||
|
||||
AllowMaintainerEdit: pr.AllowMaintainerEdit,
|
||||
|
||||
Base: &api.PRBranchInfo{
|
||||
Name: pr.BaseBranch,
|
||||
Ref: pr.BaseBranch,
|
||||
RepoID: pr.BaseRepoID,
|
||||
Repository: ToRepo(ctx, pr.BaseRepo, p.AccessMode),
|
||||
},
|
||||
Head: &api.PRBranchInfo{
|
||||
Name: pr.HeadBranch,
|
||||
Ref: fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index),
|
||||
RepoID: -1,
|
||||
},
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
|
||||
return nil
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
baseBranch, err = gitRepo.GetBranch(pr.BaseBranch)
|
||||
if err != nil && !git.IsErrBranchNotExist(err) {
|
||||
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
baseCommit, err = baseBranch.GetCommit()
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
apiPullRequest.Base.Sha = baseCommit.ID.String()
|
||||
}
|
||||
}
|
||||
|
||||
if pr.Flow == issues_model.PullRequestFlowAGit {
|
||||
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err)
|
||||
return nil
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||
if err != nil {
|
||||
log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
|
||||
return nil
|
||||
}
|
||||
apiPullRequest.Head.RepoID = pr.BaseRepoID
|
||||
apiPullRequest.Head.Repository = apiPullRequest.Base.Repository
|
||||
apiPullRequest.Head.Name = ""
|
||||
}
|
||||
|
||||
if pr.HeadRepo != nil && pr.Flow == issues_model.PullRequestFlowGithub {
|
||||
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.AccessMode)
|
||||
|
||||
headGitRepo, err := git.OpenRepository(ctx, pr.HeadRepo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err)
|
||||
return nil
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
if err == nil {
|
||||
apiPullRequest.Head.Ref = pr.HeadBranch
|
||||
apiPullRequest.Head.Sha = commit.ID.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {
|
||||
baseGitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
|
||||
return nil
|
||||
}
|
||||
defer baseGitRepo.Close()
|
||||
refs, err := baseGitRepo.GetRefsFiltered(apiPullRequest.Head.Ref)
|
||||
if err != nil {
|
||||
log.Error("GetRefsFiltered[%s]: %v", apiPullRequest.Head.Ref, err)
|
||||
return nil
|
||||
} else if len(refs) == 0 {
|
||||
log.Error("unable to resolve PR head ref")
|
||||
} else {
|
||||
apiPullRequest.Head.Sha = refs[0].Object.String()
|
||||
}
|
||||
}
|
||||
|
||||
if pr.HasMerged {
|
||||
apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
|
||||
apiPullRequest.MergedCommitID = &pr.MergedCommitID
|
||||
apiPullRequest.MergedBy = ToUser(pr.Merger, nil)
|
||||
}
|
||||
|
||||
return apiPullRequest
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToPullReview convert a review to api format
|
||||
func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model.User) (*api.PullReview, error) {
|
||||
if err := r.LoadAttributes(ctx); err != nil {
|
||||
if !user_model.IsErrUserNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
r.Reviewer = user_model.NewGhostUser()
|
||||
}
|
||||
|
||||
apiTeam, err := ToTeam(r.ReviewerTeam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &api.PullReview{
|
||||
ID: r.ID,
|
||||
Reviewer: ToUser(r.Reviewer, doer),
|
||||
ReviewerTeam: apiTeam,
|
||||
State: api.ReviewStateUnknown,
|
||||
Body: r.Content,
|
||||
CommitID: r.CommitID,
|
||||
Stale: r.Stale,
|
||||
Official: r.Official,
|
||||
Dismissed: r.Dismissed,
|
||||
CodeCommentsCount: r.GetCodeCommentsCount(),
|
||||
Submitted: r.CreatedUnix.AsTime(),
|
||||
Updated: r.UpdatedUnix.AsTime(),
|
||||
HTMLURL: r.HTMLURL(),
|
||||
HTMLPullURL: r.Issue.HTMLURL(),
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case issues_model.ReviewTypeApprove:
|
||||
result.State = api.ReviewStateApproved
|
||||
case issues_model.ReviewTypeReject:
|
||||
result.State = api.ReviewStateRequestChanges
|
||||
case issues_model.ReviewTypeComment:
|
||||
result.State = api.ReviewStateComment
|
||||
case issues_model.ReviewTypePending:
|
||||
result.State = api.ReviewStatePending
|
||||
case issues_model.ReviewTypeRequest:
|
||||
result.State = api.ReviewStateRequestReview
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ToPullReviewList convert a list of review to it's api format
|
||||
func ToPullReviewList(ctx context.Context, rl []*issues_model.Review, doer *user_model.User) ([]*api.PullReview, error) {
|
||||
result := make([]*api.PullReview, 0, len(rl))
|
||||
for i := range rl {
|
||||
// show pending reviews only for the user who created them
|
||||
if rl[i].Type == issues_model.ReviewTypePending && !(doer.IsAdmin || doer.ID == rl[i].ReviewerID) {
|
||||
continue
|
||||
}
|
||||
r, err := ToPullReview(ctx, rl[i], doer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, r)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ToPullReviewCommentList convert the CodeComments of an review to it's api format
|
||||
func ToPullReviewCommentList(ctx context.Context, review *issues_model.Review, doer *user_model.User) ([]*api.PullReviewComment, error) {
|
||||
if err := review.LoadAttributes(ctx); err != nil {
|
||||
if !user_model.IsErrUserNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
review.Reviewer = user_model.NewGhostUser()
|
||||
}
|
||||
|
||||
apiComments := make([]*api.PullReviewComment, 0, len(review.CodeComments))
|
||||
|
||||
for _, lines := range review.CodeComments {
|
||||
for _, comments := range lines {
|
||||
for _, comment := range comments {
|
||||
apiComment := &api.PullReviewComment{
|
||||
ID: comment.ID,
|
||||
Body: comment.Content,
|
||||
Poster: ToUser(comment.Poster, doer),
|
||||
Resolver: ToUser(comment.ResolveDoer, doer),
|
||||
ReviewID: review.ID,
|
||||
Created: comment.CreatedUnix.AsTime(),
|
||||
Updated: comment.UpdatedUnix.AsTime(),
|
||||
Path: comment.TreePath,
|
||||
CommitID: comment.CommitSHA,
|
||||
OrigCommitID: comment.OldRef,
|
||||
DiffHunk: patch2diff(comment.Patch),
|
||||
HTMLURL: comment.HTMLURL(),
|
||||
HTMLPullURL: review.Issue.HTMLURL(),
|
||||
}
|
||||
|
||||
if comment.Line < 0 {
|
||||
apiComment.OldLineNum = comment.UnsignedLine()
|
||||
} else {
|
||||
apiComment.LineNum = comment.UnsignedLine()
|
||||
}
|
||||
apiComments = append(apiComments, apiComment)
|
||||
}
|
||||
}
|
||||
}
|
||||
return apiComments, nil
|
||||
}
|
||||
|
||||
func patch2diff(patch string) string {
|
||||
split := strings.Split(patch, "\n@@")
|
||||
if len(split) == 2 {
|
||||
return "@@" + split[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPullRequest_APIFormat(t *testing.T) {
|
||||
// with HeadRepo
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadAttributes(db.DefaultContext))
|
||||
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
|
||||
apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil)
|
||||
assert.NotNil(t, apiPullRequest)
|
||||
assert.EqualValues(t, &structs.PRBranchInfo{
|
||||
Name: "branch1",
|
||||
Ref: "refs/pull/2/head",
|
||||
Sha: "4a357436d925b5c974181ff12a994538ddc5a269",
|
||||
RepoID: 1,
|
||||
Repository: ToRepo(db.DefaultContext, headRepo, perm.AccessModeRead),
|
||||
}, apiPullRequest.Head)
|
||||
|
||||
// withOut HeadRepo
|
||||
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
|
||||
assert.NoError(t, pr.LoadAttributes(db.DefaultContext))
|
||||
// simulate fork deletion
|
||||
pr.HeadRepo = nil
|
||||
pr.HeadRepoID = 100000
|
||||
apiPullRequest = ToAPIPullRequest(git.DefaultContext, pr, nil)
|
||||
assert.NotNil(t, apiPullRequest)
|
||||
assert.Nil(t, apiPullRequest.Head.Repository)
|
||||
assert.EqualValues(t, -1, apiPullRequest.Head.RepoID)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToRelease convert a repo_model.Release to api.Release
|
||||
func ToRelease(r *repo_model.Release) *api.Release {
|
||||
return &api.Release{
|
||||
ID: r.ID,
|
||||
TagName: r.TagName,
|
||||
Target: r.Target,
|
||||
Title: r.Title,
|
||||
Note: r.Note,
|
||||
URL: r.APIURL(),
|
||||
HTMLURL: r.HTMLURL(),
|
||||
TarURL: r.TarURL(),
|
||||
ZipURL: r.ZipURL(),
|
||||
IsDraft: r.IsDraft,
|
||||
IsPrerelease: r.IsPrerelease,
|
||||
CreatedAt: r.CreatedUnix.AsTime(),
|
||||
PublishedAt: r.CreatedUnix.AsTime(),
|
||||
Publisher: ToUser(r.Publisher, nil),
|
||||
Attachments: ToAttachments(r.Attachments),
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToRepo converts a Repository to api.Repository
|
||||
func ToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode) *api.Repository {
|
||||
return innerToRepo(ctx, repo, mode, false)
|
||||
}
|
||||
|
||||
func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode, isParent bool) *api.Repository {
|
||||
var parent *api.Repository
|
||||
|
||||
cloneLink := repo.CloneLink()
|
||||
permission := &api.Permission{
|
||||
Admin: mode >= perm.AccessModeAdmin,
|
||||
Push: mode >= perm.AccessModeWrite,
|
||||
Pull: mode >= perm.AccessModeRead,
|
||||
}
|
||||
if !isParent {
|
||||
err := repo.GetBaseRepo(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if repo.BaseRepo != nil {
|
||||
parent = innerToRepo(ctx, repo.BaseRepo, mode, true)
|
||||
}
|
||||
}
|
||||
|
||||
// check enabled/disabled units
|
||||
hasIssues := false
|
||||
var externalTracker *api.ExternalTracker
|
||||
var internalTracker *api.InternalTracker
|
||||
if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err == nil {
|
||||
config := unit.IssuesConfig()
|
||||
hasIssues = true
|
||||
internalTracker = &api.InternalTracker{
|
||||
EnableTimeTracker: config.EnableTimetracker,
|
||||
AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
|
||||
EnableIssueDependencies: config.EnableDependencies,
|
||||
}
|
||||
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil {
|
||||
config := unit.ExternalTrackerConfig()
|
||||
hasIssues = true
|
||||
externalTracker = &api.ExternalTracker{
|
||||
ExternalTrackerURL: config.ExternalTrackerURL,
|
||||
ExternalTrackerFormat: config.ExternalTrackerFormat,
|
||||
ExternalTrackerStyle: config.ExternalTrackerStyle,
|
||||
ExternalTrackerRegexpPattern: config.ExternalTrackerRegexpPattern,
|
||||
}
|
||||
}
|
||||
hasWiki := false
|
||||
var externalWiki *api.ExternalWiki
|
||||
if _, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil {
|
||||
hasWiki = true
|
||||
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil {
|
||||
hasWiki = true
|
||||
config := unit.ExternalWikiConfig()
|
||||
externalWiki = &api.ExternalWiki{
|
||||
ExternalWikiURL: config.ExternalWikiURL,
|
||||
}
|
||||
}
|
||||
hasPullRequests := false
|
||||
ignoreWhitespaceConflicts := false
|
||||
allowMerge := false
|
||||
allowRebase := false
|
||||
allowRebaseMerge := false
|
||||
allowSquash := false
|
||||
allowRebaseUpdate := false
|
||||
defaultDeleteBranchAfterMerge := false
|
||||
defaultMergeStyle := repo_model.MergeStyleMerge
|
||||
if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil {
|
||||
config := unit.PullRequestsConfig()
|
||||
hasPullRequests = true
|
||||
ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
|
||||
allowMerge = config.AllowMerge
|
||||
allowRebase = config.AllowRebase
|
||||
allowRebaseMerge = config.AllowRebaseMerge
|
||||
allowSquash = config.AllowSquash
|
||||
allowRebaseUpdate = config.AllowRebaseUpdate
|
||||
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
|
||||
defaultMergeStyle = config.GetDefaultMergeStyle()
|
||||
}
|
||||
hasProjects := false
|
||||
if _, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil {
|
||||
hasProjects = true
|
||||
}
|
||||
|
||||
if err := repo.GetOwner(ctx); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false})
|
||||
|
||||
mirrorInterval := ""
|
||||
var mirrorUpdated time.Time
|
||||
if repo.IsMirror {
|
||||
var err error
|
||||
repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID)
|
||||
if err == nil {
|
||||
mirrorInterval = repo.Mirror.Interval.String()
|
||||
mirrorUpdated = repo.Mirror.UpdatedUnix.AsTime()
|
||||
}
|
||||
}
|
||||
|
||||
var transfer *api.RepoTransfer
|
||||
if repo.Status == repo_model.RepositoryPendingTransfer {
|
||||
t, err := models.GetPendingRepositoryTransfer(ctx, repo)
|
||||
if err != nil && !models.IsErrNoPendingTransfer(err) {
|
||||
log.Warn("GetPendingRepositoryTransfer: %v", err)
|
||||
} else {
|
||||
if err := t.LoadAttributes(ctx); err != nil {
|
||||
log.Warn("LoadAttributes of RepoTransfer: %v", err)
|
||||
} else {
|
||||
transfer = ToRepoTransfer(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var language string
|
||||
if repo.PrimaryLanguage != nil {
|
||||
language = repo.PrimaryLanguage.Language
|
||||
}
|
||||
|
||||
repoAPIURL := repo.APIURL()
|
||||
|
||||
return &api.Repository{
|
||||
ID: repo.ID,
|
||||
Owner: ToUserWithAccessMode(repo.Owner, mode),
|
||||
Name: repo.Name,
|
||||
FullName: repo.FullName(),
|
||||
Description: repo.Description,
|
||||
Private: repo.IsPrivate,
|
||||
Template: repo.IsTemplate,
|
||||
Empty: repo.IsEmpty,
|
||||
Archived: repo.IsArchived,
|
||||
Size: int(repo.Size / 1024),
|
||||
Fork: repo.IsFork,
|
||||
Parent: parent,
|
||||
Mirror: repo.IsMirror,
|
||||
HTMLURL: repo.HTMLURL(),
|
||||
SSHURL: cloneLink.SSH,
|
||||
CloneURL: cloneLink.HTTPS,
|
||||
OriginalURL: repo.SanitizedOriginalURL(),
|
||||
Website: repo.Website,
|
||||
Language: language,
|
||||
LanguagesURL: repoAPIURL + "/languages",
|
||||
Stars: repo.NumStars,
|
||||
Forks: repo.NumForks,
|
||||
Watchers: repo.NumWatches,
|
||||
OpenIssues: repo.NumOpenIssues,
|
||||
OpenPulls: repo.NumOpenPulls,
|
||||
Releases: int(numReleases),
|
||||
DefaultBranch: repo.DefaultBranch,
|
||||
Created: repo.CreatedUnix.AsTime(),
|
||||
Updated: repo.UpdatedUnix.AsTime(),
|
||||
Permissions: permission,
|
||||
HasIssues: hasIssues,
|
||||
ExternalTracker: externalTracker,
|
||||
InternalTracker: internalTracker,
|
||||
HasWiki: hasWiki,
|
||||
HasProjects: hasProjects,
|
||||
ExternalWiki: externalWiki,
|
||||
HasPullRequests: hasPullRequests,
|
||||
IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts,
|
||||
AllowMerge: allowMerge,
|
||||
AllowRebase: allowRebase,
|
||||
AllowRebaseMerge: allowRebaseMerge,
|
||||
AllowSquash: allowSquash,
|
||||
AllowRebaseUpdate: allowRebaseUpdate,
|
||||
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
|
||||
DefaultMergeStyle: string(defaultMergeStyle),
|
||||
AvatarURL: repo.AvatarLink(),
|
||||
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
|
||||
MirrorInterval: mirrorInterval,
|
||||
MirrorUpdated: mirrorUpdated,
|
||||
RepoTransfer: transfer,
|
||||
}
|
||||
}
|
||||
|
||||
// ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
|
||||
func ToRepoTransfer(t *models.RepoTransfer) *api.RepoTransfer {
|
||||
teams, _ := ToTeams(t.Teams, false)
|
||||
|
||||
return &api.RepoTransfer{
|
||||
Doer: ToUser(t.Doer, nil),
|
||||
Recipient: ToUser(t.Recipient, nil),
|
||||
Teams: teams,
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToCommitStatus converts git_model.CommitStatus to api.CommitStatus
|
||||
func ToCommitStatus(ctx context.Context, status *git_model.CommitStatus) *api.CommitStatus {
|
||||
apiStatus := &api.CommitStatus{
|
||||
Created: status.CreatedUnix.AsTime(),
|
||||
Updated: status.CreatedUnix.AsTime(),
|
||||
State: status.State,
|
||||
TargetURL: status.TargetURL,
|
||||
Description: status.Description,
|
||||
ID: status.Index,
|
||||
URL: status.APIURL(),
|
||||
Context: status.Context,
|
||||
}
|
||||
|
||||
if status.CreatorID != 0 {
|
||||
creator, _ := user_model.GetUserByID(ctx, status.CreatorID)
|
||||
apiStatus.Creator = ToUser(creator, nil)
|
||||
}
|
||||
|
||||
return apiStatus
|
||||
}
|
||||
|
||||
// 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,
|
||||
TotalCount: len(statuses),
|
||||
Repository: repo,
|
||||
URL: "",
|
||||
}
|
||||
|
||||
retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses))
|
||||
for _, status := range statuses {
|
||||
retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status))
|
||||
if status.State.NoBetterThan(retStatus.State) {
|
||||
retStatus.State = status.State
|
||||
}
|
||||
}
|
||||
|
||||
return retStatus
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToUser convert user_model.User to api.User
|
||||
// if doer is set, private information is added if the doer has the permission to see it
|
||||
func ToUser(user, doer *user_model.User) *api.User {
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
authed := false
|
||||
signed := false
|
||||
if doer != nil {
|
||||
signed = true
|
||||
authed = doer.ID == user.ID || doer.IsAdmin
|
||||
}
|
||||
return toUser(user, signed, authed)
|
||||
}
|
||||
|
||||
// ToUsers convert list of user_model.User to list of api.User
|
||||
func ToUsers(doer *user_model.User, users []*user_model.User) []*api.User {
|
||||
result := make([]*api.User, len(users))
|
||||
for i := range users {
|
||||
result[i] = ToUser(users[i], doer)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ToUserWithAccessMode convert user_model.User to api.User
|
||||
// AccessMode is not none show add some more information
|
||||
func ToUserWithAccessMode(user *user_model.User, accessMode perm.AccessMode) *api.User {
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
return toUser(user, accessMode != perm.AccessModeNone, false)
|
||||
}
|
||||
|
||||
// toUser convert user_model.User to api.User
|
||||
// signed shall only be set if requester is logged in. authed shall only be set if user is site admin or user himself
|
||||
func toUser(user *user_model.User, signed, authed bool) *api.User {
|
||||
result := &api.User{
|
||||
ID: user.ID,
|
||||
UserName: user.Name,
|
||||
FullName: user.FullName,
|
||||
Email: user.GetEmail(),
|
||||
AvatarURL: user.AvatarLink(),
|
||||
Created: user.CreatedUnix.AsTime(),
|
||||
Restricted: user.IsRestricted,
|
||||
Location: user.Location,
|
||||
Website: user.Website,
|
||||
Description: user.Description,
|
||||
// counter's
|
||||
Followers: user.NumFollowers,
|
||||
Following: user.NumFollowing,
|
||||
StarredRepos: user.NumStars,
|
||||
}
|
||||
|
||||
result.Visibility = user.Visibility.String()
|
||||
|
||||
// hide primary email if API caller is anonymous or user keep email private
|
||||
if signed && (!user.KeepEmailPrivate || authed) {
|
||||
result.Email = user.Email
|
||||
}
|
||||
|
||||
// only site admin will get these information and possibly user himself
|
||||
if authed {
|
||||
result.IsAdmin = user.IsAdmin
|
||||
result.LoginName = user.LoginName
|
||||
result.LastLogin = user.LastLoginUnix.AsTime()
|
||||
result.Language = user.Language
|
||||
result.IsActive = user.IsActive
|
||||
result.ProhibitLogin = user.ProhibitLogin
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// User2UserSettings return UserSettings based on a user
|
||||
func User2UserSettings(user *user_model.User) api.UserSettings {
|
||||
return api.UserSettings{
|
||||
FullName: user.FullName,
|
||||
Website: user.Website,
|
||||
Location: user.Location,
|
||||
Language: user.Language,
|
||||
Description: user.Description,
|
||||
Theme: user.Theme,
|
||||
HideEmail: user.KeepEmailPrivate,
|
||||
HideActivity: user.KeepActivityPrivate,
|
||||
DiffViewStyle: user.DiffViewStyle,
|
||||
}
|
||||
}
|
||||
|
||||
// ToUserAndPermission return User and its collaboration permission for a repository
|
||||
func ToUserAndPermission(user, doer *user_model.User, accessMode perm.AccessMode) api.RepoCollaboratorPermission {
|
||||
return api.RepoCollaboratorPermission{
|
||||
User: ToUser(user, doer),
|
||||
Permission: accessMode.String(),
|
||||
RoleName: accessMode.String(),
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUser_ToUser(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1, IsAdmin: true})
|
||||
|
||||
apiUser := toUser(user1, true, true)
|
||||
assert.True(t, apiUser.IsAdmin)
|
||||
assert.Contains(t, apiUser.AvatarURL, "://")
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2, IsAdmin: false})
|
||||
|
||||
apiUser = toUser(user2, true, true)
|
||||
assert.False(t, apiUser.IsAdmin)
|
||||
|
||||
apiUser = toUser(user1, false, false)
|
||||
assert.False(t, apiUser.IsAdmin)
|
||||
assert.EqualValues(t, api.VisibleTypePublic.String(), apiUser.Visibility)
|
||||
|
||||
user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate})
|
||||
|
||||
apiUser = toUser(user31, true, true)
|
||||
assert.False(t, apiUser.IsAdmin)
|
||||
assert.EqualValues(t, api.VisibleTypePrivate.String(), apiUser.Visibility)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2016 The Gogs Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ToCorrectPageSize makes sure page size is in allowed range.
|
||||
func ToCorrectPageSize(size int) int {
|
||||
if size <= 0 {
|
||||
size = setting.API.DefaultPagingNum
|
||||
} else if size > setting.API.MaxResponseItems {
|
||||
size = setting.API.MaxResponseItems
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// ToGitServiceType return GitServiceType based on string
|
||||
func ToGitServiceType(value string) structs.GitServiceType {
|
||||
switch strings.ToLower(value) {
|
||||
case "github":
|
||||
return structs.GithubService
|
||||
case "gitea":
|
||||
return structs.GiteaService
|
||||
case "gitlab":
|
||||
return structs.GitlabService
|
||||
case "gogs":
|
||||
return structs.GogsService
|
||||
case "onedev":
|
||||
return structs.OneDevService
|
||||
case "gitbucket":
|
||||
return structs.GitBucketService
|
||||
default:
|
||||
return structs.PlainGitService
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
func TestToGitServiceType(t *testing.T) {
|
||||
tc := []struct {
|
||||
typ string
|
||||
enum int
|
||||
}{{
|
||||
typ: "github", enum: 2,
|
||||
}, {
|
||||
typ: "gitea", enum: 3,
|
||||
}, {
|
||||
typ: "gitlab", enum: 4,
|
||||
}, {
|
||||
typ: "gogs", enum: 5,
|
||||
}, {
|
||||
typ: "trash", enum: 1,
|
||||
}}
|
||||
for _, test := range tc {
|
||||
assert.EqualValues(t, test.enum, ToGitServiceType(test.typ))
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
wiki_service "code.gitea.io/gitea/services/wiki"
|
||||
)
|
||||
|
||||
// ToWikiCommit convert a git commit into a WikiCommit
|
||||
func ToWikiCommit(commit *git.Commit) *api.WikiCommit {
|
||||
return &api.WikiCommit{
|
||||
ID: commit.ID.String(),
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
},
|
||||
Date: commit.Author.When.UTC().Format(time.RFC3339),
|
||||
},
|
||||
Committer: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: commit.Committer.Name,
|
||||
Email: commit.Committer.Email,
|
||||
},
|
||||
Date: commit.Committer.When.UTC().Format(time.RFC3339),
|
||||
},
|
||||
Message: commit.CommitMessage,
|
||||
}
|
||||
}
|
||||
|
||||
// ToWikiCommitList convert a list of git commits into a WikiCommitList
|
||||
func ToWikiCommitList(commits []*git.Commit, total int64) *api.WikiCommitList {
|
||||
result := make([]*api.WikiCommit, len(commits))
|
||||
for i := range commits {
|
||||
result[i] = ToWikiCommit(commits[i])
|
||||
}
|
||||
return &api.WikiCommitList{
|
||||
WikiCommits: result,
|
||||
Count: total,
|
||||
}
|
||||
}
|
||||
|
||||
// ToWikiPageMetaData converts meta information to a WikiPageMetaData
|
||||
func ToWikiPageMetaData(title string, lastCommit *git.Commit, repo *repo_model.Repository) *api.WikiPageMetaData {
|
||||
suburl := wiki_service.NameToSubURL(title)
|
||||
return &api.WikiPageMetaData{
|
||||
Title: title,
|
||||
HTMLURL: util.URLJoin(repo.HTMLURL(), "wiki", suburl),
|
||||
SubURL: suburl,
|
||||
LastCommit: ToWikiCommit(lastCommit),
|
||||
}
|
||||
}
|
||||
+1625
-1404
File diff suppressed because it is too large
Load Diff
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
)
|
||||
|
||||
// Init starts this eventsource
|
||||
|
||||
+31
-45
@@ -9,10 +9,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
)
|
||||
|
||||
// BlamePart represents block of blame - continuous lines with one sha
|
||||
@@ -23,12 +20,11 @@ type BlamePart struct {
|
||||
|
||||
// BlameReader returns part of file blame one by one
|
||||
type BlameReader struct {
|
||||
cmd *exec.Cmd
|
||||
output io.ReadCloser
|
||||
reader *bufio.Reader
|
||||
lastSha *string
|
||||
cancel context.CancelFunc // Cancels the context that this reader runs in
|
||||
finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
|
||||
cmd *Command
|
||||
output io.WriteCloser
|
||||
reader io.ReadCloser
|
||||
done chan error
|
||||
lastSha *string
|
||||
}
|
||||
|
||||
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
|
||||
@@ -37,7 +33,7 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
|
||||
func (r *BlameReader) NextPart() (*BlamePart, error) {
|
||||
var blamePart *BlamePart
|
||||
|
||||
reader := r.reader
|
||||
reader := bufio.NewReader(r.reader)
|
||||
|
||||
if r.lastSha != nil {
|
||||
blamePart = &BlamePart{*r.lastSha, make([]string, 0)}
|
||||
@@ -99,51 +95,41 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
|
||||
|
||||
// Close BlameReader - don't run NextPart after invoking that
|
||||
func (r *BlameReader) Close() error {
|
||||
defer r.finished() // Only remove the process from the process table when the underlying command is closed
|
||||
r.cancel() // However, first cancel our own context early
|
||||
|
||||
err := <-r.done
|
||||
_ = r.reader.Close()
|
||||
_ = r.output.Close()
|
||||
|
||||
if err := r.cmd.Wait(); err != nil {
|
||||
return fmt.Errorf("Wait: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateBlameReader creates reader for given repository, commit and file
|
||||
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
|
||||
return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
|
||||
}
|
||||
|
||||
func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) {
|
||||
// Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
|
||||
ctx, cancel, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("GetBlame [repo_path: %s]", dir))
|
||||
|
||||
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||
cmd.Dir = dir
|
||||
cmd.Stderr = os.Stderr
|
||||
process.SetSysProcAttribute(cmd)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
cmd := NewCommandContextNoGlobals(ctx, "blame", "--porcelain").
|
||||
AddDynamicArguments(commitID).
|
||||
AddDashesAndList(file).
|
||||
SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath))
|
||||
reader, stdout, err := os.Pipe()
|
||||
if err != nil {
|
||||
defer finished()
|
||||
return nil, fmt.Errorf("StdoutPipe: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
defer finished()
|
||||
_ = stdout.Close()
|
||||
return nil, fmt.Errorf("Start: %w", err)
|
||||
}
|
||||
done := make(chan error, 1)
|
||||
|
||||
reader := bufio.NewReader(stdout)
|
||||
go func(cmd *Command, dir string, stdout io.WriteCloser, done chan error) {
|
||||
if err := cmd.Run(&RunOpts{
|
||||
UseContextTimeout: true,
|
||||
Dir: dir,
|
||||
Stdout: stdout,
|
||||
Stderr: os.Stderr,
|
||||
}); err == nil {
|
||||
stdout.Close()
|
||||
}
|
||||
done <- err
|
||||
}(cmd, repoPath, stdout, done)
|
||||
|
||||
return &BlameReader{
|
||||
cmd: cmd,
|
||||
output: stdout,
|
||||
reader: reader,
|
||||
cancel: cancel,
|
||||
finished: finished,
|
||||
cmd: cmd,
|
||||
output: stdout,
|
||||
reader: reader,
|
||||
done: done,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+8
-111
@@ -5,139 +5,36 @@ package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const exampleBlame = `
|
||||
4b92a6c2df28054ad766bc262f308db9f6066596 1 1 1
|
||||
author Unknown
|
||||
author-mail <joe2010xtmf@163.com>
|
||||
author-time 1392833071
|
||||
author-tz -0500
|
||||
committer Unknown
|
||||
committer-mail <joe2010xtmf@163.com>
|
||||
committer-time 1392833071
|
||||
committer-tz -0500
|
||||
summary Add code of delete user
|
||||
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
|
||||
filename gogs.go
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
ce21ed6c3490cdfad797319cbb1145e2330a8fef 2 2 1
|
||||
author Joubert RedRat
|
||||
author-mail <eu+github@redrat.com.br>
|
||||
author-time 1482322397
|
||||
author-tz -0200
|
||||
committer Lunny Xiao
|
||||
committer-mail <xiaolunwen@gmail.com>
|
||||
committer-time 1482322397
|
||||
committer-tz +0800
|
||||
summary Remove remaining Gogs reference on locales and cmd (#430)
|
||||
previous 618407c018cdf668ceedde7454c42fb22ba422d8 main.go
|
||||
filename main.go
|
||||
// Copyright 2016 The Gitea Authors. All rights reserved.
|
||||
4b92a6c2df28054ad766bc262f308db9f6066596 2 3 2
|
||||
author Unknown
|
||||
author-mail <joe2010xtmf@163.com>
|
||||
author-time 1392833071
|
||||
author-tz -0500
|
||||
committer Unknown
|
||||
committer-mail <joe2010xtmf@163.com>
|
||||
committer-time 1392833071
|
||||
committer-tz -0500
|
||||
summary Add code of delete user
|
||||
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
|
||||
filename gogs.go
|
||||
// Use of this source code is governed by a MIT-style
|
||||
4b92a6c2df28054ad766bc262f308db9f6066596 3 4
|
||||
author Unknown
|
||||
author-mail <joe2010xtmf@163.com>
|
||||
author-time 1392833071
|
||||
author-tz -0500
|
||||
committer Unknown
|
||||
committer-mail <joe2010xtmf@163.com>
|
||||
committer-time 1392833071
|
||||
committer-tz -0500
|
||||
summary Add code of delete user
|
||||
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
|
||||
filename gogs.go
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
e2aa991e10ffd924a828ec149951f2f20eecead2 6 6 2
|
||||
author Lunny Xiao
|
||||
author-mail <xiaolunwen@gmail.com>
|
||||
author-time 1478872595
|
||||
author-tz +0800
|
||||
committer Sandro Santilli
|
||||
committer-mail <strk@kbt.io>
|
||||
committer-time 1478872595
|
||||
committer-tz +0100
|
||||
summary ask for go get from code.gitea.io/gitea and change gogs to gitea on main file (#146)
|
||||
previous 5fc370e332171b8658caed771b48585576f11737 main.go
|
||||
filename main.go
|
||||
// Gitea (git with a cup of tea) is a painless self-hosted Git Service.
|
||||
e2aa991e10ffd924a828ec149951f2f20eecead2 7 7
|
||||
package main // import "code.gitea.io/gitea"
|
||||
`
|
||||
|
||||
func TestReadingBlameOutput(t *testing.T) {
|
||||
tempFile, err := os.CreateTemp("", ".txt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer tempFile.Close()
|
||||
|
||||
if _, err = tempFile.WriteString(exampleBlame); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blameReader, err := createBlameReader(ctx, "", "cat", tempFile.Name())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", "f32b0a9dfd09a60f616f29158f772cedd89942d2", "README.md")
|
||||
assert.NoError(t, err)
|
||||
defer blameReader.Close()
|
||||
|
||||
parts := []*BlamePart{
|
||||
{
|
||||
"4b92a6c2df28054ad766bc262f308db9f6066596",
|
||||
"72866af952e98d02a73003501836074b286a78f6",
|
||||
[]string{
|
||||
"// Copyright 2014 The Gogs Authors. All rights reserved.",
|
||||
"# test_repo",
|
||||
"Test repository for testing migration from github to gitea",
|
||||
},
|
||||
},
|
||||
{
|
||||
"ce21ed6c3490cdfad797319cbb1145e2330a8fef",
|
||||
[]string{
|
||||
"// Copyright 2016 The Gitea Authors. All rights reserved.",
|
||||
},
|
||||
"f32b0a9dfd09a60f616f29158f772cedd89942d2",
|
||||
[]string{},
|
||||
},
|
||||
{
|
||||
"4b92a6c2df28054ad766bc262f308db9f6066596",
|
||||
[]string{
|
||||
"// Use of this source code is governed by a MIT-style",
|
||||
"// license that can be found in the LICENSE file.",
|
||||
"",
|
||||
},
|
||||
},
|
||||
{
|
||||
"e2aa991e10ffd924a828ec149951f2f20eecead2",
|
||||
[]string{
|
||||
"// Gitea (git with a cup of tea) is a painless self-hosted Git Service.",
|
||||
"package main // import \"code.gitea.io/gitea\"",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
}
|
||||
|
||||
for _, part := range parts {
|
||||
actualPart, err := blameReader.NextPart()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, part, actualPart)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func (repo *Repository) RemoveReference(name string) error {
|
||||
|
||||
// ConvertToSHA1 returns a Hash object from a potential ID string
|
||||
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
|
||||
if len(commitID) == 40 {
|
||||
if len(commitID) == SHAFullLength {
|
||||
sha1, err := NewIDFromString(commitID)
|
||||
if err == nil {
|
||||
return sha1, nil
|
||||
|
||||
@@ -137,7 +137,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
|
||||
|
||||
// ConvertToSHA1 returns a Hash object from a potential ID string
|
||||
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
|
||||
if len(commitID) == 40 && IsValidSHAPattern(commitID) {
|
||||
if len(commitID) == SHAFullLength && IsValidSHAPattern(commitID) {
|
||||
sha1, err := NewIDFromString(commitID)
|
||||
if err == nil {
|
||||
return sha1, nil
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
|
||||
// ReadTreeToIndex reads a treeish to the index
|
||||
func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error {
|
||||
if len(treeish) != 40 {
|
||||
if len(treeish) != SHAFullLength {
|
||||
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(&RunOpts{Dir: repo.Path})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -19,7 +19,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
||||
|
||||
// GetTree find the tree object in the repository.
|
||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||
if len(idStr) != 40 {
|
||||
if len(idStr) != SHAFullLength {
|
||||
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(&RunOpts{Dir: repo.Path})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -66,7 +66,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
||||
|
||||
// GetTree find the tree object in the repository.
|
||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||
if len(idStr) != 40 {
|
||||
if len(idStr) != SHAFullLength {
|
||||
res, err := repo.GetRefCommitID(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+4
-1
@@ -17,6 +17,9 @@ const EmptySHA = "0000000000000000000000000000000000000000"
|
||||
// EmptyTreeSHA is the SHA of an empty tree
|
||||
const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
|
||||
// SHAFullLength is the full length of a git SHA
|
||||
const SHAFullLength = 40
|
||||
|
||||
// SHAPattern can be used to determine if a string is an valid sha
|
||||
var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
||||
|
||||
@@ -50,7 +53,7 @@ func MustIDFromString(s string) SHA1 {
|
||||
func NewIDFromString(s string) (SHA1, error) {
|
||||
var id SHA1
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) != 40 {
|
||||
if len(s) != SHAFullLength {
|
||||
return id, fmt.Errorf("Length must be 40: %s", s)
|
||||
}
|
||||
b, err := hex.DecodeString(s)
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/notification/mail"
|
||||
"code.gitea.io/gitea/modules/notification/mirror"
|
||||
"code.gitea.io/gitea/modules/notification/ui"
|
||||
"code.gitea.io/gitea/modules/notification/webhook"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
@@ -36,7 +35,6 @@ func NewContext() {
|
||||
RegisterNotifier(mail.NewNotifier())
|
||||
}
|
||||
RegisterNotifier(indexer.NewNotifier())
|
||||
RegisterNotifier(webhook.NewNotifier())
|
||||
RegisterNotifier(action.NewNotifier())
|
||||
RegisterNotifier(mirror.NewNotifier())
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ func (ns *notificationService) NotifyPullReviewRequest(ctx context.Context, doer
|
||||
}
|
||||
|
||||
func (ns *notificationService) NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) {
|
||||
err := db.AutoTx(ctx, func(ctx context.Context) error {
|
||||
err := db.WithTx(ctx, func(ctx context.Context) error {
|
||||
return activities_model.CreateRepoTransferNotification(ctx, doer, newOwner, repo)
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,856 +0,0 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
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/models/webhook"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification/base"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
webhook_services "code.gitea.io/gitea/services/webhook"
|
||||
)
|
||||
|
||||
type webhookNotifier struct {
|
||||
base.NullNotifier
|
||||
}
|
||||
|
||||
var _ base.Notifier = &webhookNotifier{}
|
||||
|
||||
// NewNotifier create a new webhookNotifier notifier
|
||||
func NewNotifier() base.Notifier {
|
||||
return &webhookNotifier{}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) {
|
||||
if err := issue.LoadPoster(ctx); err != nil {
|
||||
log.Error("LoadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("LoadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
var err error
|
||||
if issue.IsPull {
|
||||
if err = issue.LoadPullRequest(ctx); err != nil {
|
||||
log.Error("LoadPullRequest: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{
|
||||
Action: api.HookIssueLabelCleared,
|
||||
Index: issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
} else {
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueLabel, &api.IssuePayload{
|
||||
Action: api.HookIssueLabelCleared,
|
||||
Index: issue.Index,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) {
|
||||
oldMode, _ := access_model.AccessLevel(ctx, doer, oldRepo)
|
||||
mode, _ := access_model.AccessLevel(ctx, doer, repo)
|
||||
|
||||
// forked webhook
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: oldRepo}, webhook.HookEventFork, &api.ForkPayload{
|
||||
Forkee: convert.ToRepo(ctx, oldRepo, oldMode),
|
||||
Repo: convert.ToRepo(ctx, repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
|
||||
}
|
||||
|
||||
u := repo.MustOwner(ctx)
|
||||
|
||||
// Add to hook queue for created repo after session commit.
|
||||
if u.IsOrganization() {
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{
|
||||
Action: api.HookRepoCreated,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Organization: convert.ToUser(u, nil),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
|
||||
// Add to hook queue for created repo after session commit.
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{
|
||||
Action: api.HookRepoCreated,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Organization: convert.ToUser(u, nil),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) {
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{
|
||||
Action: api.HookRepoDeleted,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Organization: convert.ToUser(repo.MustOwner(ctx), nil),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
|
||||
// Add to hook queue for created repo after session commit.
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{
|
||||
Action: api.HookRepoCreated,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Organization: convert.ToUser(u, nil),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
|
||||
if issue.IsPull {
|
||||
mode, _ := access_model.AccessLevelUnit(ctx, doer, issue.Repo, unit.TypePullRequests)
|
||||
|
||||
if err := issue.LoadPullRequest(ctx); err != nil {
|
||||
log.Error("LoadPullRequest failed: %v", err)
|
||||
return
|
||||
}
|
||||
issue.PullRequest.Issue = issue
|
||||
apiPullRequest := &api.PullRequestPayload{
|
||||
Index: issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}
|
||||
if removed {
|
||||
apiPullRequest.Action = api.HookIssueUnassigned
|
||||
} else {
|
||||
apiPullRequest.Action = api.HookIssueAssigned
|
||||
}
|
||||
// Assignee comment triggers a webhook
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestAssign, apiPullRequest); err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
mode, _ := access_model.AccessLevelUnit(ctx, doer, issue.Repo, unit.TypeIssues)
|
||||
apiIssue := &api.IssuePayload{
|
||||
Index: issue.Index,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}
|
||||
if removed {
|
||||
apiIssue.Action = api.HookIssueUnassigned
|
||||
} else {
|
||||
apiIssue.Action = api.HookIssueAssigned
|
||||
}
|
||||
// Assignee comment triggers a webhook
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueAssign, apiIssue); err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
var err error
|
||||
if issue.IsPull {
|
||||
if err = issue.LoadPullRequest(ctx); err != nil {
|
||||
log.Error("LoadPullRequest failed: %v", err)
|
||||
return
|
||||
}
|
||||
issue.PullRequest.Issue = issue
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{
|
||||
Action: api.HookIssueEdited,
|
||||
Index: issue.Index,
|
||||
Changes: &api.ChangesPayload{
|
||||
Title: &api.ChangesFromPayload{
|
||||
From: oldTitle,
|
||||
},
|
||||
},
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
} else {
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{
|
||||
Action: api.HookIssueEdited,
|
||||
Index: issue.Index,
|
||||
Changes: &api.ChangesPayload{
|
||||
Title: &api.ChangesFromPayload{
|
||||
From: oldTitle,
|
||||
},
|
||||
},
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
var err error
|
||||
if issue.IsPull {
|
||||
if err = issue.LoadPullRequest(ctx); err != nil {
|
||||
log.Error("LoadPullRequest: %v", err)
|
||||
return
|
||||
}
|
||||
// Merge pull request calls issue.changeStatus so we need to handle separately.
|
||||
apiPullRequest := &api.PullRequestPayload{
|
||||
Index: issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}
|
||||
if isClosed {
|
||||
apiPullRequest.Action = api.HookIssueClosed
|
||||
} else {
|
||||
apiPullRequest.Action = api.HookIssueReOpened
|
||||
}
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, apiPullRequest)
|
||||
} else {
|
||||
apiIssue := &api.IssuePayload{
|
||||
Index: issue.Index,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}
|
||||
if isClosed {
|
||||
apiIssue.Action = api.HookIssueClosed
|
||||
} else {
|
||||
apiIssue.Action = api.HookIssueReOpened
|
||||
}
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, apiIssue)
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) {
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("issue.LoadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
if err := issue.LoadPoster(ctx); err != nil {
|
||||
log.Error("issue.LoadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{
|
||||
Action: api.HookIssueOpened,
|
||||
Index: issue.Index,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(issue.Poster, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues_model.PullRequest, mentions []*user_model.User) {
|
||||
if err := pull.LoadIssue(ctx); err != nil {
|
||||
log.Error("pull.LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
if err := pull.Issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("pull.Issue.LoadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
if err := pull.Issue.LoadPoster(ctx); err != nil {
|
||||
log.Error("pull.Issue.LoadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, pull.Issue.Poster, pull.Issue.Repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pull.Issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{
|
||||
Action: api.HookIssueOpened,
|
||||
Index: pull.Issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, pull, nil),
|
||||
Repository: convert.ToRepo(ctx, pull.Issue.Repo, mode),
|
||||
Sender: convert.ToUser(pull.Issue.Poster, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("LoadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
var err error
|
||||
if issue.IsPull {
|
||||
issue.PullRequest.Issue = issue
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{
|
||||
Action: api.HookIssueEdited,
|
||||
Index: issue.Index,
|
||||
Changes: &api.ChangesPayload{
|
||||
Body: &api.ChangesFromPayload{
|
||||
From: oldContent,
|
||||
},
|
||||
},
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
} else {
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{
|
||||
Action: api.HookIssueEdited,
|
||||
Index: issue.Index,
|
||||
Changes: &api.ChangesPayload{
|
||||
Body: &api.ChangesFromPayload{
|
||||
From: oldContent,
|
||||
},
|
||||
},
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyUpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) {
|
||||
if err := c.LoadPoster(ctx); err != nil {
|
||||
log.Error("LoadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
if err := c.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.Issue.LoadAttributes(ctx); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var eventType webhook.HookEventType
|
||||
if c.Issue.IsPull {
|
||||
eventType = webhook.HookEventPullRequestComment
|
||||
} else {
|
||||
eventType = webhook.HookEventIssueComment
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, doer, c.Issue.Repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{
|
||||
Action: api.HookIssueCommentEdited,
|
||||
Issue: convert.ToAPIIssue(ctx, c.Issue),
|
||||
Comment: convert.ToComment(c),
|
||||
Changes: &api.ChangesPayload{
|
||||
Body: &api.ChangesFromPayload{
|
||||
From: oldContent,
|
||||
},
|
||||
},
|
||||
Repository: convert.ToRepo(ctx, c.Issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
IsPull: c.Issue.IsPull,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository,
|
||||
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
|
||||
) {
|
||||
var eventType webhook.HookEventType
|
||||
if issue.IsPull {
|
||||
eventType = webhook.HookEventPullRequestComment
|
||||
} else {
|
||||
eventType = webhook.HookEventIssueComment
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, doer, repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{
|
||||
Action: api.HookIssueCommentCreated,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Comment: convert.ToComment(comment),
|
||||
Repository: convert.ToRepo(ctx, repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
IsPull: issue.IsPull,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyDeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) {
|
||||
var err error
|
||||
|
||||
if err = comment.LoadPoster(ctx); err != nil {
|
||||
log.Error("LoadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
if err = comment.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = comment.Issue.LoadAttributes(ctx); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var eventType webhook.HookEventType
|
||||
if comment.Issue.IsPull {
|
||||
eventType = webhook.HookEventPullRequestComment
|
||||
} else {
|
||||
eventType = webhook.HookEventIssueComment
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, doer, comment.Issue.Repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{
|
||||
Action: api.HookIssueCommentDeleted,
|
||||
Issue: convert.ToAPIIssue(ctx, comment.Issue),
|
||||
Comment: convert.ToComment(comment),
|
||||
Repository: convert.ToRepo(ctx, comment.Issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
IsPull: comment.Issue.IsPull,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyNewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) {
|
||||
// Add to hook queue for created wiki page.
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{
|
||||
Action: api.HookWikiCreated,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
Page: page,
|
||||
Comment: comment,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyEditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) {
|
||||
// Add to hook queue for edit wiki page.
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{
|
||||
Action: api.HookWikiEdited,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
Page: page,
|
||||
Comment: comment,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyDeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) {
|
||||
// Add to hook queue for edit wiki page.
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{
|
||||
Action: api.HookWikiDeleted,
|
||||
Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
Page: page,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
|
||||
addedLabels, removedLabels []*issues_model.Label,
|
||||
) {
|
||||
var err error
|
||||
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("LoadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.LoadPoster(ctx); err != nil {
|
||||
log.Error("LoadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
if issue.IsPull {
|
||||
if err = issue.LoadPullRequest(ctx); err != nil {
|
||||
log.Error("loadPullRequest: %v", err)
|
||||
return
|
||||
}
|
||||
if err = issue.PullRequest.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{
|
||||
Action: api.HookIssueLabelUpdated,
|
||||
Index: issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, perm.AccessModeNone),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
} else {
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueLabel, &api.IssuePayload{
|
||||
Action: api.HookIssueLabelUpdated,
|
||||
Index: issue.Index,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
|
||||
var hookAction api.HookIssueAction
|
||||
var err error
|
||||
if issue.MilestoneID > 0 {
|
||||
hookAction = api.HookIssueMilestoned
|
||||
} else {
|
||||
hookAction = api.HookIssueDemilestoned
|
||||
}
|
||||
|
||||
if err = issue.LoadAttributes(ctx); err != nil {
|
||||
log.Error("issue.LoadAttributes failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, doer, issue.Repo)
|
||||
if issue.IsPull {
|
||||
err = issue.PullRequest.LoadIssue(ctx)
|
||||
if err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestMilestone, &api.PullRequestPayload{
|
||||
Action: hookAction,
|
||||
Index: issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
} else {
|
||||
err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueMilestone, &api.IssuePayload{
|
||||
Action: hookAction,
|
||||
Index: issue.Index,
|
||||
Issue: convert.ToAPIIssue(ctx, issue),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
|
||||
apiPusher := convert.ToUser(pusher, nil)
|
||||
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
|
||||
if err != nil {
|
||||
log.Error("commits.ToAPIPayloadCommits failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventPush, &api.PushPayload{
|
||||
Ref: opts.RefFullName,
|
||||
Before: opts.OldCommitID,
|
||||
After: opts.NewCommitID,
|
||||
CompareURL: setting.AppURL + commits.CompareURL,
|
||||
Commits: apiCommits,
|
||||
TotalCommits: commits.Len,
|
||||
HeadCommit: apiHeadCommit,
|
||||
Repo: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Pusher: apiPusher,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
|
||||
// just redirect to the NotifyMergePullRequest
|
||||
m.NotifyMergePullRequest(ctx, doer, pr)
|
||||
}
|
||||
|
||||
func (*webhookNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
|
||||
// Reload pull request information.
|
||||
if err := pr.LoadAttributes(ctx); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.Issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("pr.Issue.LoadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, err := access_model.AccessLevel(ctx, doer, pr.Issue.Repo)
|
||||
if err != nil {
|
||||
log.Error("models.AccessLevel: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Merge pull request calls issue.changeStatus so we need to handle separately.
|
||||
apiPullRequest := &api.PullRequestPayload{
|
||||
Index: pr.Issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
|
||||
Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
Action: api.HookIssueClosed,
|
||||
}
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pr.Issue.Repo}, webhook.HookEventPullRequest, apiPullRequest); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) {
|
||||
if err := pr.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
issue := pr.Issue
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{
|
||||
Action: api.HookIssueEdited,
|
||||
Index: issue.Index,
|
||||
Changes: &api.ChangesPayload{
|
||||
Ref: &api.ChangesFromPayload{
|
||||
From: oldBranch,
|
||||
},
|
||||
},
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
|
||||
Repository: convert.ToRepo(ctx, issue.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [pr: %d]: %v", pr.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
|
||||
var reviewHookType webhook.HookEventType
|
||||
|
||||
switch review.Type {
|
||||
case issues_model.ReviewTypeApprove:
|
||||
reviewHookType = webhook.HookEventPullRequestReviewApproved
|
||||
case issues_model.ReviewTypeComment:
|
||||
reviewHookType = webhook.HookEventPullRequestComment
|
||||
case issues_model.ReviewTypeReject:
|
||||
reviewHookType = webhook.HookEventPullRequestReviewRejected
|
||||
default:
|
||||
// unsupported review webhook type here
|
||||
log.Error("Unsupported review webhook type")
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, err := access_model.AccessLevel(ctx, review.Issue.Poster, review.Issue.Repo)
|
||||
if err != nil {
|
||||
log.Error("models.AccessLevel: %v", err)
|
||||
return
|
||||
}
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: review.Issue.Repo}, reviewHookType, &api.PullRequestPayload{
|
||||
Action: api.HookIssueReviewed,
|
||||
Index: review.Issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
|
||||
Repository: convert.ToRepo(ctx, review.Issue.Repo, mode),
|
||||
Sender: convert.ToUser(review.Reviewer, nil),
|
||||
Review: &api.ReviewPayload{
|
||||
Type: string(reviewHookType),
|
||||
Content: review.Content,
|
||||
},
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
|
||||
apiPusher := convert.ToUser(pusher, nil)
|
||||
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
|
||||
refName := git.RefEndName(refFullName)
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventCreate, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
Sha: refID,
|
||||
RefType: refType,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyPullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
|
||||
if err := pr.LoadIssue(ctx); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
if err := pr.Issue.LoadAttributes(ctx); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pr.Issue.Repo}, webhook.HookEventPullRequestSync, &api.PullRequestPayload{
|
||||
Action: api.HookIssueSynchronized,
|
||||
Index: pr.Issue.Index,
|
||||
PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
|
||||
Repository: convert.ToRepo(ctx, pr.Issue.Repo, perm.AccessModeNone),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) {
|
||||
apiPusher := convert.ToUser(pusher, nil)
|
||||
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
|
||||
refName := git.RefEndName(refFullName)
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventDelete, &api.DeletePayload{
|
||||
Ref: refName,
|
||||
RefType: refType,
|
||||
PusherType: api.PusherTypeUser,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks.(delete %s): %v", refType, err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model.Release, action api.HookReleaseAction) {
|
||||
if err := rel.LoadAttributes(ctx); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := access_model.AccessLevel(ctx, doer, rel.Repo)
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: rel.Repo}, webhook.HookEventRelease, &api.ReleasePayload{
|
||||
Action: action,
|
||||
Release: convert.ToRelease(rel),
|
||||
Repository: convert.ToRepo(ctx, rel.Repo, mode),
|
||||
Sender: convert.ToUser(doer, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.Release) {
|
||||
sendReleaseHook(ctx, rel.Publisher, rel, api.HookReleasePublished)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyUpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) {
|
||||
sendReleaseHook(ctx, doer, rel, api.HookReleaseUpdated)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyDeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) {
|
||||
sendReleaseHook(ctx, doer, rel, api.HookReleaseDeleted)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
|
||||
apiPusher := convert.ToUser(pusher, nil)
|
||||
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
|
||||
if err != nil {
|
||||
log.Error("commits.ToAPIPayloadCommits failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventPush, &api.PushPayload{
|
||||
Ref: opts.RefFullName,
|
||||
Before: opts.OldCommitID,
|
||||
After: opts.NewCommitID,
|
||||
CompareURL: setting.AppURL + commits.CompareURL,
|
||||
Commits: apiCommits,
|
||||
TotalCommits: commits.Len,
|
||||
HeadCommit: apiHeadCommit,
|
||||
Repo: convert.ToRepo(ctx, repo, perm.AccessModeOwner),
|
||||
Pusher: apiPusher,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
|
||||
m.NotifyCreateRef(ctx, pusher, repo, refType, refFullName, refID)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) {
|
||||
m.NotifyDeleteRef(ctx, pusher, repo, refType, refFullName)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) {
|
||||
notifyPackage(ctx, doer, pd, api.HookPackageCreated)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) NotifyPackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) {
|
||||
notifyPackage(ctx, doer, pd, api.HookPackageDeleted)
|
||||
}
|
||||
|
||||
func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) {
|
||||
source := webhook_services.EventSource{
|
||||
Repository: pd.Repository,
|
||||
Owner: pd.Owner,
|
||||
}
|
||||
|
||||
apiPackage, err := convert.ToPackage(ctx, pd, sender)
|
||||
if err != nil {
|
||||
log.Error("Error converting package: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := webhook_services.PrepareWebhooks(ctx, source, webhook.HookEventPackage, &api.PackagePayload{
|
||||
Action: action,
|
||||
Package: apiPackage,
|
||||
Sender: convert.ToUser(sender, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,12 @@ package composer
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
@@ -21,11 +21,11 @@ const TypeProperty = "composer.type"
|
||||
|
||||
var (
|
||||
// ErrMissingComposerFile indicates a missing composer.json file
|
||||
ErrMissingComposerFile = errors.New("composer.json file is missing")
|
||||
ErrMissingComposerFile = util.NewInvalidArgumentErrorf("composer.json file is missing")
|
||||
// ErrInvalidName indicates an invalid package name
|
||||
ErrInvalidName = errors.New("package name is invalid")
|
||||
ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
|
||||
// ErrInvalidVersion indicates an invalid package version
|
||||
ErrInvalidVersion = errors.New("package version is invalid")
|
||||
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
|
||||
)
|
||||
|
||||
// Package represents a Composer package
|
||||
|
||||
@@ -5,9 +5,10 @@ package conan
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// Conaninfo represents infos of a Conan package
|
||||
@@ -79,7 +80,7 @@ func readSections(r io.Reader) (map[string][]string, error) {
|
||||
continue
|
||||
}
|
||||
if line != "" {
|
||||
return nil, errors.New("Invalid conaninfo.txt")
|
||||
return nil, util.NewInvalidArgumentErrorf("invalid conaninfo.txt")
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
package conan
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,7 +25,7 @@ var (
|
||||
namePattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9_][a-zA-Z0-9_\+\.-]{%d,%d}$`, minChars-1, maxChars-1))
|
||||
revisionPattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9]{1,%d}$`, maxChars))
|
||||
|
||||
ErrValidation = errors.New("Could not validate one or more reference fields")
|
||||
ErrValidation = util.NewInvalidArgumentErrorf("could not validate one or more reference fields")
|
||||
)
|
||||
|
||||
// RecipeReference represents a recipe <Name>/<Version>@<User>/<Channel>#<Revision>
|
||||
|
||||
@@ -6,10 +6,10 @@ package helm
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
@@ -18,13 +18,13 @@ import (
|
||||
|
||||
var (
|
||||
// ErrMissingChartFile indicates a missing Chart.yaml file
|
||||
ErrMissingChartFile = errors.New("Chart.yaml file is missing")
|
||||
ErrMissingChartFile = util.NewInvalidArgumentErrorf("Chart.yaml file is missing")
|
||||
// ErrInvalidName indicates an invalid package name
|
||||
ErrInvalidName = errors.New("package name is invalid")
|
||||
ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
|
||||
// ErrInvalidVersion indicates an invalid package version
|
||||
ErrInvalidVersion = errors.New("package version is invalid")
|
||||
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
|
||||
// ErrInvalidChart indicates an invalid chart
|
||||
ErrInvalidChart = errors.New("chart is invalid")
|
||||
ErrInvalidChart = util.NewInvalidArgumentErrorf("chart is invalid")
|
||||
)
|
||||
|
||||
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
@@ -16,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
@@ -23,15 +23,15 @@ import (
|
||||
|
||||
var (
|
||||
// ErrInvalidPackage indicates an invalid package
|
||||
ErrInvalidPackage = errors.New("The package is invalid")
|
||||
ErrInvalidPackage = util.NewInvalidArgumentErrorf("package is invalid")
|
||||
// ErrInvalidPackageName indicates an invalid name
|
||||
ErrInvalidPackageName = errors.New("The package name is invalid")
|
||||
ErrInvalidPackageName = util.NewInvalidArgumentErrorf("package name is invalid")
|
||||
// ErrInvalidPackageVersion indicates an invalid version
|
||||
ErrInvalidPackageVersion = errors.New("The package version is invalid")
|
||||
ErrInvalidPackageVersion = util.NewInvalidArgumentErrorf("package version is invalid")
|
||||
// ErrInvalidAttachment indicates a invalid attachment
|
||||
ErrInvalidAttachment = errors.New("The package attachment is invalid")
|
||||
ErrInvalidAttachment = util.NewInvalidArgumentErrorf("package attachment is invalid")
|
||||
// ErrInvalidIntegrity indicates an integrity validation error
|
||||
ErrInvalidIntegrity = errors.New("Failed to validate integrity")
|
||||
ErrInvalidIntegrity = util.NewInvalidArgumentErrorf("failed to validate integrity")
|
||||
)
|
||||
|
||||
var nameMatch = regexp.MustCompile(`\A((@[^\s\/~'!\(\)\*]+?)[\/])?([^_.][^\s\/~'!\(\)\*]+)\z`)
|
||||
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
@@ -21,13 +21,13 @@ import (
|
||||
|
||||
var (
|
||||
// ErrMissingNuspecFile indicates a missing Nuspec file
|
||||
ErrMissingNuspecFile = errors.New("Nuspec file is missing")
|
||||
ErrMissingNuspecFile = util.NewInvalidArgumentErrorf("Nuspec file is missing")
|
||||
// ErrNuspecFileTooLarge indicates a Nuspec file which is too large
|
||||
ErrNuspecFileTooLarge = errors.New("Nuspec file is too large")
|
||||
ErrNuspecFileTooLarge = util.NewInvalidArgumentErrorf("Nuspec file is too large")
|
||||
// ErrNuspecInvalidID indicates an invalid id in the Nuspec file
|
||||
ErrNuspecInvalidID = errors.New("Nuspec file contains an invalid id")
|
||||
ErrNuspecInvalidID = util.NewInvalidArgumentErrorf("Nuspec file contains an invalid id")
|
||||
// ErrNuspecInvalidVersion indicates an invalid version in the Nuspec file
|
||||
ErrNuspecInvalidVersion = errors.New("Nuspec file contains an invalid version")
|
||||
ErrNuspecInvalidVersion = util.NewInvalidArgumentErrorf("Nuspec file contains an invalid version")
|
||||
)
|
||||
|
||||
// PackageType specifies the package type the metadata describes
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
@@ -15,13 +14,14 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/packages"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingPdbFiles = errors.New("Package does not contain PDB files")
|
||||
ErrInvalidFiles = errors.New("Package contains invalid files")
|
||||
ErrInvalidPdbMagicNumber = errors.New("Invalid Portable PDB magic number")
|
||||
ErrMissingPdbStream = errors.New("Missing PDB stream")
|
||||
ErrMissingPdbFiles = util.NewInvalidArgumentErrorf("package does not contain PDB files")
|
||||
ErrInvalidFiles = util.NewInvalidArgumentErrorf("package contains invalid files")
|
||||
ErrInvalidPdbMagicNumber = util.NewInvalidArgumentErrorf("invalid Portable PDB magic number")
|
||||
ErrMissingPdbStream = util.NewInvalidArgumentErrorf("missing PDB stream")
|
||||
)
|
||||
|
||||
type PortablePdb struct {
|
||||
|
||||
@@ -6,11 +6,11 @@ package pub
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingPubspecFile = errors.New("Pubspec file is missing")
|
||||
ErrPubspecFileTooLarge = errors.New("Pubspec file is too large")
|
||||
ErrInvalidName = errors.New("Package name is invalid")
|
||||
ErrInvalidVersion = errors.New("Package version is invalid")
|
||||
ErrMissingPubspecFile = util.NewInvalidArgumentErrorf("Pubspec file is missing")
|
||||
ErrPubspecFileTooLarge = util.NewInvalidArgumentErrorf("Pubspec file is too large")
|
||||
ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
|
||||
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
|
||||
)
|
||||
|
||||
var namePattern = regexp.MustCompile(`\A[a-zA-Z_][a-zA-Z0-9_]*\z`)
|
||||
|
||||
@@ -6,9 +6,10 @@ package rubygems
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -31,9 +32,9 @@ const (
|
||||
|
||||
var (
|
||||
// ErrUnsupportedType indicates an unsupported type
|
||||
ErrUnsupportedType = errors.New("Type is unsupported")
|
||||
ErrUnsupportedType = util.NewInvalidArgumentErrorf("type is unsupported")
|
||||
// ErrInvalidIntRange indicates an invalid number range
|
||||
ErrInvalidIntRange = errors.New("Number is not in valid range")
|
||||
ErrInvalidIntRange = util.NewInvalidArgumentErrorf("number is not in valid range")
|
||||
)
|
||||
|
||||
// RubyUserMarshal is a Ruby object that has a marshal_load function.
|
||||
|
||||
@@ -6,11 +6,11 @@ package rubygems
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
|
||||
var (
|
||||
// ErrMissingMetadataFile indicates a missing metadata.gz file
|
||||
ErrMissingMetadataFile = errors.New("Metadata file is missing")
|
||||
ErrMissingMetadataFile = util.NewInvalidArgumentErrorf("metadata.gz file is missing")
|
||||
// ErrInvalidName indicates an invalid id in the metadata.gz file
|
||||
ErrInvalidName = errors.New("Metadata file contains an invalid name")
|
||||
ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
|
||||
// ErrInvalidVersion indicates an invalid version in the metadata.gz file
|
||||
ErrInvalidVersion = errors.New("Metadata file contains an invalid version")
|
||||
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
|
||||
)
|
||||
|
||||
var versionMatcher = regexp.MustCompile(`\A[0-9]+(?:\.[0-9a-zA-Z]+)*(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?\z`)
|
||||
|
||||
@@ -109,32 +109,6 @@ func (q *ChannelQueue) Flush(timeout time.Duration) error {
|
||||
return q.FlushWithContext(ctx)
|
||||
}
|
||||
|
||||
// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty
|
||||
func (q *ChannelQueue) FlushWithContext(ctx context.Context) error {
|
||||
log.Trace("ChannelQueue: %d Flush", q.qid)
|
||||
paused, _ := q.IsPausedIsResumed()
|
||||
for {
|
||||
select {
|
||||
case <-paused:
|
||||
return nil
|
||||
case data, ok := <-q.dataChan:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if unhandled := q.handle(data); unhandled != nil {
|
||||
log.Error("Unhandled Data whilst flushing queue %d", q.qid)
|
||||
}
|
||||
atomic.AddInt64(&q.numInQueue, -1)
|
||||
case <-q.baseCtx.Done():
|
||||
return q.baseCtx.Err()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown processing from this queue
|
||||
func (q *ChannelQueue) Shutdown() {
|
||||
q.lock.Lock()
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"runtime/pprof"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
@@ -167,35 +166,6 @@ func (q *ChannelUniqueQueue) Flush(timeout time.Duration) error {
|
||||
return q.FlushWithContext(ctx)
|
||||
}
|
||||
|
||||
// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty
|
||||
func (q *ChannelUniqueQueue) FlushWithContext(ctx context.Context) error {
|
||||
log.Trace("ChannelUniqueQueue: %d Flush", q.qid)
|
||||
paused, _ := q.IsPausedIsResumed()
|
||||
for {
|
||||
select {
|
||||
case <-paused:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
select {
|
||||
case data, ok := <-q.dataChan:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if unhandled := q.handle(data); unhandled != nil {
|
||||
log.Error("Unhandled Data whilst flushing queue %d", q.qid)
|
||||
}
|
||||
atomic.AddInt64(&q.numInQueue, -1)
|
||||
case <-q.baseCtx.Done():
|
||||
return q.baseCtx.Err()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown processing from this queue
|
||||
func (q *ChannelUniqueQueue) Shutdown() {
|
||||
log.Trace("ChannelUniqueQueue: %s Shutting down", q.name)
|
||||
|
||||
@@ -463,13 +463,43 @@ func (p *WorkerPool) IsEmpty() bool {
|
||||
return atomic.LoadInt64(&p.numInQueue) == 0
|
||||
}
|
||||
|
||||
// contextError returns either ctx.Done(), the base context's error or nil
|
||||
func (p *WorkerPool) contextError(ctx context.Context) error {
|
||||
select {
|
||||
case <-p.baseCtx.Done():
|
||||
return p.baseCtx.Err()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty
|
||||
// NB: The worker will not be registered with the manager.
|
||||
func (p *WorkerPool) FlushWithContext(ctx context.Context) error {
|
||||
log.Trace("WorkerPool: %d Flush", p.qid)
|
||||
paused, _ := p.IsPausedIsResumed()
|
||||
for {
|
||||
// Because select will return any case that is satisified at random we precheck here before looking at dataChan.
|
||||
select {
|
||||
case data := <-p.dataChan:
|
||||
case <-paused:
|
||||
// Ensure that even if paused that the cancelled error is still sent
|
||||
return p.contextError(ctx)
|
||||
case <-p.baseCtx.Done():
|
||||
return p.baseCtx.Err()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case <-paused:
|
||||
return p.contextError(ctx)
|
||||
case data, ok := <-p.dataChan:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if unhandled := p.handle(data); unhandled != nil {
|
||||
log.Error("Unhandled Data whilst flushing queue %d", p.qid)
|
||||
}
|
||||
@@ -495,6 +525,7 @@ func (p *WorkerPool) doWork(ctx context.Context) {
|
||||
paused, _ := p.IsPausedIsResumed()
|
||||
data := make([]Data, 0, p.batchLength)
|
||||
for {
|
||||
// Because select will return any case that is satisified at random we precheck here before looking at dataChan.
|
||||
select {
|
||||
case <-paused:
|
||||
log.Trace("Worker for Queue %d Pausing", p.qid)
|
||||
@@ -515,8 +546,19 @@ func (p *WorkerPool) doWork(ctx context.Context) {
|
||||
log.Trace("Worker shutting down")
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
if len(data) > 0 {
|
||||
log.Trace("Handling: %d data, %v", len(data), data)
|
||||
if unhandled := p.handle(data...); unhandled != nil {
|
||||
log.Error("Unhandled Data in queue %d", p.qid)
|
||||
}
|
||||
atomic.AddInt64(&p.numInQueue, -1*int64(len(data)))
|
||||
}
|
||||
log.Trace("Worker shutting down")
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case <-paused:
|
||||
// go back around
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func AddCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error {
|
||||
return db.AutoTx(ctx, func(ctx context.Context) error {
|
||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||
collaboration := &repo_model.Collaboration{
|
||||
RepoID: repo.ID,
|
||||
UserID: u.ID,
|
||||
|
||||
@@ -394,7 +394,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
|
||||
defer content.Close()
|
||||
|
||||
_, err := git_model.NewLFSMetaObject(&git_model.LFSMetaObject{Pointer: p, RepositoryID: repo.ID})
|
||||
_, err := git_model.NewLFSMetaObject(ctx, &git_model.LFSMetaObject{Pointer: p, RepositoryID: repo.ID})
|
||||
if err != nil {
|
||||
log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, p, err)
|
||||
return err
|
||||
@@ -402,7 +402,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
|
||||
if err := contentStore.Put(p, content); err != nil {
|
||||
log.Error("Repo[%-v]: Error storing content for LFS meta object %-v: %v", repo, p, err)
|
||||
if _, err2 := git_model.RemoveLFSMetaObjectByOid(repo.ID, p.Oid); err2 != nil {
|
||||
if _, err2 := git_model.RemoveLFSMetaObjectByOid(ctx, repo.ID, p.Oid); err2 != nil {
|
||||
log.Error("Repo[%-v]: Error removing LFS meta object %-v: %v", repo, p, err2)
|
||||
}
|
||||
return err
|
||||
@@ -421,7 +421,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
|
||||
var batch []lfs.Pointer
|
||||
for pointerBlob := range pointerChan {
|
||||
meta, err := git_model.GetLFSMetaObjectByOid(repo.ID, pointerBlob.Oid)
|
||||
meta, err := git_model.GetLFSMetaObjectByOid(ctx, repo.ID, pointerBlob.Oid)
|
||||
if err != nil && err != git_model.ErrLFSObjectNotExist {
|
||||
log.Error("Repo[%-v]: Error querying LFS meta object %-v: %v", repo, pointerBlob.Pointer, err)
|
||||
return err
|
||||
@@ -441,7 +441,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
|
||||
if exist {
|
||||
log.Trace("Repo[%-v]: LFS object %-v already present; creating meta object", repo, pointerBlob.Pointer)
|
||||
_, err := git_model.NewLFSMetaObject(&git_model.LFSMetaObject{Pointer: pointerBlob.Pointer, RepositoryID: repo.ID})
|
||||
_, err := git_model.NewLFSMetaObject(ctx, &git_model.LFSMetaObject{Pointer: pointerBlob.Pointer, RepositoryID: repo.ID})
|
||||
if err != nil {
|
||||
log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, pointerBlob.Pointer, err)
|
||||
return err
|
||||
|
||||
+12
-17
@@ -284,8 +284,6 @@ func newRouterLogService() {
|
||||
}
|
||||
|
||||
func newLogService() {
|
||||
log.Info("Gitea v%s%s", AppVer, AppBuiltWith)
|
||||
|
||||
options := newDefaultLogOptions()
|
||||
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
|
||||
EnableSSHLog = Cfg.Section("log").Key("ENABLE_SSH_LOG").MustBool(false)
|
||||
@@ -297,24 +295,14 @@ func newLogService() {
|
||||
sections := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
|
||||
|
||||
useConsole := false
|
||||
for i := 0; i < len(sections); i++ {
|
||||
sections[i] = strings.TrimSpace(sections[i])
|
||||
if sections[i] == "console" {
|
||||
useConsole = true
|
||||
}
|
||||
}
|
||||
|
||||
if !useConsole {
|
||||
err := log.DelLogger("console")
|
||||
if err != nil {
|
||||
log.Fatal("DelLogger: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range sections {
|
||||
if len(name) == 0 {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if name == "console" {
|
||||
useConsole = true
|
||||
}
|
||||
|
||||
sec, err := Cfg.GetSection("log." + name + ".default")
|
||||
if err != nil {
|
||||
@@ -336,6 +324,13 @@ func newLogService() {
|
||||
|
||||
AddLogDescription(log.DEFAULT, &description)
|
||||
|
||||
if !useConsole {
|
||||
log.Info("According to the configuration, subsequent logs will not be printed to the console")
|
||||
if err := log.DelLogger("console"); err != nil {
|
||||
log.Fatal("Cannot delete console logger: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally redirect the default golog to here
|
||||
golog.SetFlags(0)
|
||||
golog.SetPrefix("")
|
||||
|
||||
@@ -68,7 +68,7 @@ func newPictureService() {
|
||||
}
|
||||
|
||||
func GetDefaultDisableGravatar() bool {
|
||||
return !OfflineMode
|
||||
return OfflineMode
|
||||
}
|
||||
|
||||
func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool {
|
||||
|
||||
@@ -48,6 +48,7 @@ var (
|
||||
AllowAdoptionOfUnadoptedRepositories bool
|
||||
AllowDeleteOfUnadoptedRepositories bool
|
||||
DisableDownloadSourceArchives bool
|
||||
AllowForkWithoutMaximumLimit bool
|
||||
|
||||
// Repository editor settings
|
||||
Editor struct {
|
||||
@@ -160,6 +161,7 @@ var (
|
||||
DisableMigrations: false,
|
||||
DisableStars: false,
|
||||
DefaultBranch: "main",
|
||||
AllowForkWithoutMaximumLimit: true,
|
||||
|
||||
// Repository editor settings
|
||||
Editor: struct {
|
||||
|
||||
+29
-15
@@ -11,48 +11,62 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// sitemapFileLimit contains the maximum size of a sitemap file
|
||||
const sitemapFileLimit = 50 * 1024 * 1024
|
||||
const (
|
||||
sitemapFileLimit = 50 * 1024 * 1024 // the maximum size of a sitemap file
|
||||
urlsLimit = 50000
|
||||
|
||||
// Url represents a single sitemap entry
|
||||
schemaURL = "http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
urlsetName = "urlset"
|
||||
sitemapindexName = "sitemapindex"
|
||||
)
|
||||
|
||||
// URL represents a single sitemap entry
|
||||
type URL struct {
|
||||
URL string `xml:"loc"`
|
||||
LastMod *time.Time `xml:"lastmod,omitempty"`
|
||||
}
|
||||
|
||||
// SitemapUrl represents a sitemap
|
||||
// Sitemap represents a sitemap
|
||||
type Sitemap struct {
|
||||
XMLName xml.Name
|
||||
Namespace string `xml:"xmlns,attr"`
|
||||
|
||||
URLs []URL `xml:"url"`
|
||||
URLs []URL `xml:"url"`
|
||||
Sitemaps []URL `xml:"sitemap"`
|
||||
}
|
||||
|
||||
// NewSitemap creates a sitemap
|
||||
func NewSitemap() *Sitemap {
|
||||
return &Sitemap{
|
||||
XMLName: xml.Name{Local: "urlset"},
|
||||
Namespace: "http://www.sitemaps.org/schemas/sitemap/0.9",
|
||||
XMLName: xml.Name{Local: urlsetName},
|
||||
Namespace: schemaURL,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSitemap creates a sitemap index.
|
||||
// NewSitemapIndex creates a sitemap index.
|
||||
func NewSitemapIndex() *Sitemap {
|
||||
return &Sitemap{
|
||||
XMLName: xml.Name{Local: "sitemapindex"},
|
||||
Namespace: "http://www.sitemaps.org/schemas/sitemap/0.9",
|
||||
XMLName: xml.Name{Local: sitemapindexName},
|
||||
Namespace: schemaURL,
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a URL to the sitemap
|
||||
func (s *Sitemap) Add(u URL) {
|
||||
s.URLs = append(s.URLs, u)
|
||||
if s.XMLName.Local == sitemapindexName {
|
||||
s.Sitemaps = append(s.Sitemaps, u)
|
||||
} else {
|
||||
s.URLs = append(s.URLs, u)
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes the sitemap to a response
|
||||
// WriteTo writes the sitemap to a response
|
||||
func (s *Sitemap) WriteTo(w io.Writer) (int64, error) {
|
||||
if len(s.URLs) > 50000 {
|
||||
return 0, fmt.Errorf("The sitemap contains too many URLs: %d", len(s.URLs))
|
||||
if l := len(s.URLs); l > urlsLimit {
|
||||
return 0, fmt.Errorf("The sitemap contains %d URLs, but only %d are allowed", l, urlsLimit)
|
||||
}
|
||||
if l := len(s.Sitemaps); l > urlsLimit {
|
||||
return 0, fmt.Errorf("The sitemap contains %d sub-sitemaps, but only %d are allowed", l, urlsLimit)
|
||||
}
|
||||
buf := bytes.NewBufferString(xml.Header)
|
||||
if err := xml.NewEncoder(buf).Encode(s); err != nil {
|
||||
@@ -62,7 +76,7 @@ func (s *Sitemap) WriteTo(w io.Writer) (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
if buf.Len() > sitemapFileLimit {
|
||||
return 0, fmt.Errorf("The sitemap is too big: %d", buf.Len())
|
||||
return 0, fmt.Errorf("The sitemap has %d bytes, but only %d are allowed", buf.Len(), sitemapFileLimit)
|
||||
}
|
||||
return buf.WriteTo(w)
|
||||
}
|
||||
|
||||
+142
-52
@@ -6,7 +6,6 @@ package sitemap
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -14,63 +13,154 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestOk(t *testing.T) {
|
||||
testReal := func(s *Sitemap, name string, urls []URL, expected string) {
|
||||
for _, url := range urls {
|
||||
s.Add(url)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
_, err := s.WriteTo(buf)
|
||||
assert.NoError(t, nil, err)
|
||||
assert.Equal(t, xml.Header+"<"+name+" xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">"+expected+"</"+name+">\n", buf.String())
|
||||
}
|
||||
test := func(urls []URL, expected string) {
|
||||
testReal(NewSitemap(), "urlset", urls, expected)
|
||||
testReal(NewSitemapIndex(), "sitemapindex", urls, expected)
|
||||
}
|
||||
|
||||
func TestNewSitemap(t *testing.T) {
|
||||
ts := time.Unix(1651322008, 0).UTC()
|
||||
|
||||
test(
|
||||
[]URL{},
|
||||
"",
|
||||
)
|
||||
test(
|
||||
[]URL{
|
||||
{URL: "https://gitea.io/test1", LastMod: &ts},
|
||||
tests := []struct {
|
||||
name string
|
||||
urls []URL
|
||||
want string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
urls: []URL{},
|
||||
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"" +
|
||||
"</urlset>\n",
|
||||
},
|
||||
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>",
|
||||
)
|
||||
test(
|
||||
[]URL{
|
||||
{URL: "https://gitea.io/test2", LastMod: nil},
|
||||
{
|
||||
name: "regular",
|
||||
urls: []URL{
|
||||
{URL: "https://gitea.io/test1", LastMod: &ts},
|
||||
},
|
||||
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>" +
|
||||
"</urlset>\n",
|
||||
},
|
||||
"<url><loc>https://gitea.io/test2</loc></url>",
|
||||
)
|
||||
test(
|
||||
[]URL{
|
||||
{URL: "https://gitea.io/test1", LastMod: &ts},
|
||||
{URL: "https://gitea.io/test2", LastMod: nil},
|
||||
{
|
||||
name: "without lastmod",
|
||||
urls: []URL{
|
||||
{URL: "https://gitea.io/test1"},
|
||||
},
|
||||
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"<url><loc>https://gitea.io/test1</loc></url>" +
|
||||
"</urlset>\n",
|
||||
},
|
||||
{
|
||||
name: "multiple",
|
||||
urls: []URL{
|
||||
{URL: "https://gitea.io/test1", LastMod: &ts},
|
||||
{URL: "https://gitea.io/test2", LastMod: nil},
|
||||
},
|
||||
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>" +
|
||||
"<url><loc>https://gitea.io/test2</loc></url>" +
|
||||
"</urlset>\n",
|
||||
},
|
||||
{
|
||||
name: "too many urls",
|
||||
urls: make([]URL, 50001),
|
||||
wantErr: "The sitemap contains 50001 URLs, but only 50000 are allowed",
|
||||
},
|
||||
{
|
||||
name: "too big file",
|
||||
urls: []URL{
|
||||
{URL: strings.Repeat("b", 50*1024*1024+1)},
|
||||
},
|
||||
wantErr: "The sitemap has 52428932 bytes, but only 52428800 are allowed",
|
||||
},
|
||||
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>"+
|
||||
"<url><loc>https://gitea.io/test2</loc></url>",
|
||||
)
|
||||
}
|
||||
|
||||
func TestTooManyURLs(t *testing.T) {
|
||||
s := NewSitemap()
|
||||
for i := 0; i < 50001; i++ {
|
||||
s.Add(URL{URL: fmt.Sprintf("https://gitea.io/test%d", i)})
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
_, err := s.WriteTo(buf)
|
||||
assert.EqualError(t, err, "The sitemap contains too many URLs: 50001")
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := NewSitemap()
|
||||
for _, url := range tt.urls {
|
||||
s.Add(url)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
_, err := s.WriteTo(buf)
|
||||
if tt.wantErr != "" {
|
||||
assert.EqualError(t, err, tt.wantErr)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, tt.want, buf.String(), "NewSitemap()")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSitemapTooBig(t *testing.T) {
|
||||
s := NewSitemap()
|
||||
s.Add(URL{URL: strings.Repeat("b", sitemapFileLimit)})
|
||||
buf := &bytes.Buffer{}
|
||||
_, err := s.WriteTo(buf)
|
||||
assert.EqualError(t, err, "The sitemap is too big: 52428931")
|
||||
func TestNewSitemapIndex(t *testing.T) {
|
||||
ts := time.Unix(1651322008, 0).UTC()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
urls []URL
|
||||
want string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
urls: []URL{},
|
||||
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"" +
|
||||
"</sitemapindex>\n",
|
||||
},
|
||||
{
|
||||
name: "regular",
|
||||
urls: []URL{
|
||||
{URL: "https://gitea.io/test1", LastMod: &ts},
|
||||
},
|
||||
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"<sitemap><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></sitemap>" +
|
||||
"</sitemapindex>\n",
|
||||
},
|
||||
{
|
||||
name: "without lastmod",
|
||||
urls: []URL{
|
||||
{URL: "https://gitea.io/test1"},
|
||||
},
|
||||
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"<sitemap><loc>https://gitea.io/test1</loc></sitemap>" +
|
||||
"</sitemapindex>\n",
|
||||
},
|
||||
{
|
||||
name: "multiple",
|
||||
urls: []URL{
|
||||
{URL: "https://gitea.io/test1", LastMod: &ts},
|
||||
{URL: "https://gitea.io/test2", LastMod: nil},
|
||||
},
|
||||
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
|
||||
"<sitemap><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></sitemap>" +
|
||||
"<sitemap><loc>https://gitea.io/test2</loc></sitemap>" +
|
||||
"</sitemapindex>\n",
|
||||
},
|
||||
{
|
||||
name: "too many sitemaps",
|
||||
urls: make([]URL, 50001),
|
||||
wantErr: "The sitemap contains 50001 sub-sitemaps, but only 50000 are allowed",
|
||||
},
|
||||
{
|
||||
name: "too big file",
|
||||
urls: []URL{
|
||||
{URL: strings.Repeat("b", 50*1024*1024+1)},
|
||||
},
|
||||
wantErr: "The sitemap has 52428952 bytes, but only 52428800 are allowed",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := NewSitemapIndex()
|
||||
for _, url := range tt.urls {
|
||||
s.Add(url)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
_, err := s.WriteTo(buf)
|
||||
if tt.wantErr != "" {
|
||||
assert.EqualError(t, err, tt.wantErr)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, tt.want, buf.String(), "NewSitemapIndex()")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ type CreatePushMirrorOption struct {
|
||||
RemoteUsername string `json:"remote_username"`
|
||||
RemotePassword string `json:"remote_password"`
|
||||
Interval string `json:"interval"`
|
||||
SyncOnCommit bool `json:"sync_on_commit"`
|
||||
}
|
||||
|
||||
// PushMirror represents information of a push mirror
|
||||
@@ -21,4 +22,5 @@ type PushMirror struct {
|
||||
LastUpdateUnix string `json:"last_update"`
|
||||
LastError string `json:"last_error"`
|
||||
Interval string `json:"interval"`
|
||||
SyncOnCommit bool `json:"sync_on_commit"`
|
||||
}
|
||||
|
||||
@@ -75,8 +75,15 @@ func HTMLRenderer(ctx context.Context) (context.Context, *render.Render) {
|
||||
compilingTemplates = false
|
||||
if !setting.IsProd {
|
||||
watcher.CreateWatcher(ctx, "HTML Templates", &watcher.CreateWatcherOpts{
|
||||
PathsCallback: walkTemplateFiles,
|
||||
BetweenCallback: renderer.CompileTemplates,
|
||||
PathsCallback: walkTemplateFiles,
|
||||
BetweenCallback: func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Error("PANIC: %v\n%s", err, log.Stack(2))
|
||||
}
|
||||
}()
|
||||
renderer.CompileTemplates()
|
||||
},
|
||||
})
|
||||
}
|
||||
return context.WithValue(ctx, rendererKey, renderer), renderer
|
||||
|
||||
@@ -5,6 +5,7 @@ package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Common Errors forming the base of our error system
|
||||
@@ -34,3 +35,31 @@ func (w SilentWrap) Error() string {
|
||||
func (w SilentWrap) Unwrap() error {
|
||||
return w.Err
|
||||
}
|
||||
|
||||
// NewSilentWrapErrorf returns an error that formats as the given text but unwraps as the provided error
|
||||
func NewSilentWrapErrorf(unwrap error, message string, args ...interface{}) error {
|
||||
if len(args) == 0 {
|
||||
return SilentWrap{Message: message, Err: unwrap}
|
||||
}
|
||||
return SilentWrap{Message: fmt.Sprintf(message, args...), Err: unwrap}
|
||||
}
|
||||
|
||||
// NewInvalidArgumentErrorf returns an error that formats as the given text but unwraps as an ErrInvalidArgument
|
||||
func NewInvalidArgumentErrorf(message string, args ...interface{}) error {
|
||||
return NewSilentWrapErrorf(ErrInvalidArgument, message, args...)
|
||||
}
|
||||
|
||||
// NewPermissionDeniedErrorf returns an error that formats as the given text but unwraps as an ErrPermissionDenied
|
||||
func NewPermissionDeniedErrorf(message string, args ...interface{}) error {
|
||||
return NewSilentWrapErrorf(ErrPermissionDenied, message, args...)
|
||||
}
|
||||
|
||||
// NewAlreadyExistErrorf returns an error that formats as the given text but unwraps as an ErrAlreadyExist
|
||||
func NewAlreadyExistErrorf(message string, args ...interface{}) error {
|
||||
return NewSilentWrapErrorf(ErrAlreadyExist, message, args...)
|
||||
}
|
||||
|
||||
// NewNotExistErrorf returns an error that formats as the given text but unwraps as an ErrNotExist
|
||||
func NewNotExistErrorf(message string, args ...interface{}) error {
|
||||
return NewSilentWrapErrorf(ErrNotExist, message, args...)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package webhook
|
||||
|
||||
// HookEvents is a set of web hook events
|
||||
type HookEvents struct {
|
||||
Create bool `json:"create"`
|
||||
Delete bool `json:"delete"`
|
||||
Fork bool `json:"fork"`
|
||||
Issues bool `json:"issues"`
|
||||
IssueAssign bool `json:"issue_assign"`
|
||||
IssueLabel bool `json:"issue_label"`
|
||||
IssueMilestone bool `json:"issue_milestone"`
|
||||
IssueComment bool `json:"issue_comment"`
|
||||
Push bool `json:"push"`
|
||||
PullRequest bool `json:"pull_request"`
|
||||
PullRequestAssign bool `json:"pull_request_assign"`
|
||||
PullRequestLabel bool `json:"pull_request_label"`
|
||||
PullRequestMilestone bool `json:"pull_request_milestone"`
|
||||
PullRequestComment bool `json:"pull_request_comment"`
|
||||
PullRequestReview bool `json:"pull_request_review"`
|
||||
PullRequestSync bool `json:"pull_request_sync"`
|
||||
Wiki bool `json:"wiki"`
|
||||
Repository bool `json:"repository"`
|
||||
Release bool `json:"release"`
|
||||
Package bool `json:"package"`
|
||||
}
|
||||
|
||||
// HookEvent represents events that will delivery hook.
|
||||
type HookEvent struct {
|
||||
PushOnly bool `json:"push_only"`
|
||||
SendEverything bool `json:"send_everything"`
|
||||
ChooseEvents bool `json:"choose_events"`
|
||||
BranchFilter string `json:"branch_filter"`
|
||||
|
||||
HookEvents `json:"events"`
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package webhook
|
||||
|
||||
// HookEventType is the type of a hook event
|
||||
type HookEventType string
|
||||
|
||||
// Types of hook events
|
||||
const (
|
||||
HookEventCreate HookEventType = "create"
|
||||
HookEventDelete HookEventType = "delete"
|
||||
HookEventFork HookEventType = "fork"
|
||||
HookEventPush HookEventType = "push"
|
||||
HookEventIssues HookEventType = "issues"
|
||||
HookEventIssueAssign HookEventType = "issue_assign"
|
||||
HookEventIssueLabel HookEventType = "issue_label"
|
||||
HookEventIssueMilestone HookEventType = "issue_milestone"
|
||||
HookEventIssueComment HookEventType = "issue_comment"
|
||||
HookEventPullRequest HookEventType = "pull_request"
|
||||
HookEventPullRequestAssign HookEventType = "pull_request_assign"
|
||||
HookEventPullRequestLabel HookEventType = "pull_request_label"
|
||||
HookEventPullRequestMilestone HookEventType = "pull_request_milestone"
|
||||
HookEventPullRequestComment HookEventType = "pull_request_comment"
|
||||
HookEventPullRequestReviewApproved HookEventType = "pull_request_review_approved"
|
||||
HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected"
|
||||
HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment"
|
||||
HookEventPullRequestSync HookEventType = "pull_request_sync"
|
||||
HookEventWiki HookEventType = "wiki"
|
||||
HookEventRepository HookEventType = "repository"
|
||||
HookEventRelease HookEventType = "release"
|
||||
HookEventPackage HookEventType = "package"
|
||||
)
|
||||
|
||||
// Event returns the HookEventType as an event string
|
||||
func (h HookEventType) Event() string {
|
||||
switch h {
|
||||
case HookEventCreate:
|
||||
return "create"
|
||||
case HookEventDelete:
|
||||
return "delete"
|
||||
case HookEventFork:
|
||||
return "fork"
|
||||
case HookEventPush:
|
||||
return "push"
|
||||
case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone:
|
||||
return "issues"
|
||||
case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone,
|
||||
HookEventPullRequestSync:
|
||||
return "pull_request"
|
||||
case HookEventIssueComment, HookEventPullRequestComment:
|
||||
return "issue_comment"
|
||||
case HookEventPullRequestReviewApproved:
|
||||
return "pull_request_approved"
|
||||
case HookEventPullRequestReviewRejected:
|
||||
return "pull_request_rejected"
|
||||
case HookEventPullRequestReviewComment:
|
||||
return "pull_request_comment"
|
||||
case HookEventWiki:
|
||||
return "wiki"
|
||||
case HookEventRepository:
|
||||
return "repository"
|
||||
case HookEventRelease:
|
||||
return "release"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// HookType is the type of a webhook
|
||||
type HookType = string
|
||||
|
||||
// Types of webhooks
|
||||
const (
|
||||
GITEA HookType = "gitea"
|
||||
GOGS HookType = "gogs"
|
||||
SLACK HookType = "slack"
|
||||
DISCORD HookType = "discord"
|
||||
DINGTALK HookType = "dingtalk"
|
||||
TELEGRAM HookType = "telegram"
|
||||
MSTEAMS HookType = "msteams"
|
||||
FEISHU HookType = "feishu"
|
||||
MATRIX HookType = "matrix"
|
||||
WECHATWORK HookType = "wechatwork"
|
||||
PACKAGIST HookType = "packagist"
|
||||
)
|
||||
|
||||
// HookStatus is the status of a web hook
|
||||
type HookStatus int
|
||||
|
||||
// Possible statuses of a web hook
|
||||
const (
|
||||
HookStatusNone HookStatus = iota
|
||||
HookStatusSucceed
|
||||
HookStatusFail
|
||||
)
|
||||
Reference in New Issue
Block a user