Merge remote-tracking branch 'upstream/main' into limit-repo-size

Resolved Conflicts:
	models/migrations/migrations.go
This commit is contained in:
DmitryFrolovTri
2023-10-25 09:59:00 +00:00
557 changed files with 6757 additions and 6624 deletions
+3 -4
View File
@@ -29,11 +29,10 @@ func GetKeyPair(ctx context.Context, user *user_model.User) (pub, priv string, e
return pub, priv, err
}
return pub, priv, err
} else {
priv = settings[user_model.UserActivityPubPrivPem].SettingValue
pub = settings[user_model.UserActivityPubPubPem].SettingValue
return pub, priv, err
}
priv = settings[user_model.UserActivityPubPrivPem].SettingValue
pub = settings[user_model.UserActivityPubPubPem].SettingValue
return pub, priv, err
}
// GetPublicKey function returns a user's public key
-44
View File
@@ -4,16 +4,11 @@
package context
import (
"encoding/hex"
"net/http"
"strings"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
"github.com/minio/sha256-simd"
"golang.org/x/crypto/pbkdf2"
)
const CookieNameFlash = "gitea_flash"
@@ -45,42 +40,3 @@ func (ctx *Context) DeleteSiteCookie(name string) {
func (ctx *Context) GetSiteCookie(name string) string {
return middleware.GetSiteCookie(ctx.Req, name)
}
// GetSuperSecureCookie returns given cookie value from request header with secret string.
func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
val := ctx.GetSiteCookie(name)
return ctx.CookieDecrypt(secret, val)
}
// CookieDecrypt returns given value from with secret string.
func (ctx *Context) CookieDecrypt(secret, val string) (string, bool) {
if val == "" {
return "", false
}
text, err := hex.DecodeString(val)
if err != nil {
return "", false
}
key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
text, err = util.AESGCMDecrypt(key, text)
return string(text), err == nil
}
// SetSuperSecureCookie sets given cookie value to response header with secret string.
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, maxAge int) {
text := ctx.CookieEncrypt(secret, value)
ctx.SetSiteCookie(name, text, maxAge)
}
// CookieEncrypt encrypts a given value using the provided secret
func (ctx *Context) CookieEncrypt(secret, value string) string {
key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
text, err := util.AESGCMEncrypt(key, []byte(value))
if err != nil {
panic("error encrypting cookie: " + err.Error())
}
return hex.EncodeToString(text)
}
+9 -9
View File
@@ -144,18 +144,18 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use
}
// CanUseTimetracker returns whether or not a user can use the timetracker.
func (r *Repository) CanUseTimetracker(issue *issues_model.Issue, user *user_model.User) bool {
func (r *Repository) CanUseTimetracker(ctx context.Context, issue *issues_model.Issue, user *user_model.User) bool {
// Checking for following:
// 1. Is timetracker enabled
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
isAssigned, _ := issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user)
return r.Repository.IsTimetrackerEnabled(db.DefaultContext) && (!r.Repository.AllowOnlyContributorsToTrackTime(db.DefaultContext) ||
isAssigned, _ := issues_model.IsUserAssignedToIssue(ctx, issue, user)
return r.Repository.IsTimetrackerEnabled(ctx) && (!r.Repository.AllowOnlyContributorsToTrackTime(ctx) ||
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
}
// CanCreateIssueDependencies returns whether or not a user can create dependencies.
func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bool) bool {
return r.Repository.IsDependenciesEnabled(db.DefaultContext) && r.Permission.CanWriteIssuesOrPulls(isPull)
func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_model.User, isPull bool) bool {
return r.Repository.IsDependenciesEnabled(ctx) && r.Permission.CanWriteIssuesOrPulls(isPull)
}
// GetCommitsCount returns cached commit count for current view
@@ -495,10 +495,10 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
}
// Get repository.
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, repoName)
if err != nil {
if repo_model.IsErrRepoNotExist(err) {
redirectRepoID, err := repo_model.LookupRedirect(owner.ID, repoName)
redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, repoName)
if err == nil {
RedirectToRepo(ctx.Base, redirectRepoID)
} else if repo_model.IsErrRedirectNotExist(err) {
@@ -711,13 +711,13 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
// Pull request is allowed if this is a fork repository
// and base repository accepts pull requests.
if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls() {
if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls(ctx) {
canCompare = true
ctx.Data["BaseRepo"] = repo.BaseRepo
ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
ctx.Repo.PullRequest.Allowed = canPush
ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.Repo.Owner.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
} else if repo.AllowsPulls() {
} else if repo.AllowsPulls(ctx) {
// Or, this is repository accepts pull requests between branches.
canCompare = true
ctx.Data["BaseRepo"] = repo
+3 -6
View File
@@ -83,8 +83,7 @@ func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {
ctx.Repo = repo
doer = ctx.Doer
default:
assert.Fail(t, "context is not *context.Context or *context.APIContext")
return
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
}
repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
@@ -105,8 +104,7 @@ func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {
case *context.APIContext:
repo = ctx.Repo
default:
assert.Fail(t, "context is not *context.Context or *context.APIContext")
return
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
}
gitRepo, err := git.OpenRepository(ctx, repo.Repository.RepoPath())
@@ -130,8 +128,7 @@ func LoadUser(t *testing.T, ctx gocontext.Context, userID int64) {
case *context.APIContext:
ctx.Doer = doer
default:
assert.Fail(t, "context is not *context.Context or *context.APIContext")
return
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
}
}
+1 -1
View File
@@ -74,7 +74,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
pr.MergeBase = strings.TrimSpace(pr.MergeBase)
if pr.MergeBase != oldMergeBase {
if autofix {
if err := pr.UpdateCols("merge_base"); err != nil {
if err := pr.UpdateCols(ctx, "merge_base"); err != nil {
logger.Critical("Failed to update merge_base. ERROR: %v", err)
return fmt.Errorf("Failed to update merge_base. ERROR: %w", err)
}
+1 -1
View File
@@ -74,7 +74,7 @@ func checkHooks(ctx context.Context, logger log.Logger, autofix bool) error {
func checkUserStarNum(ctx context.Context, logger log.Logger, autofix bool) error {
if autofix {
if err := models.DoctorUserStarNum(); err != nil {
if err := models.DoctorUserStarNum(ctx); err != nil {
logger.Critical("Unable update User Stars numbers")
return err
}
+75
View File
@@ -0,0 +1,75 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package doctor
import (
"context"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
repo_service "code.gitea.io/gitea/services/repository"
"xorm.io/builder"
)
func handleDeleteOrphanedRepos(ctx context.Context, logger log.Logger, autofix bool) error {
test := &consistencyCheck{
Name: "Repos with no existing owner",
Counter: countOrphanedRepos,
Fixer: deleteOrphanedRepos,
FixedMessage: "Deleted all content related to orphaned repos",
}
return test.Run(ctx, logger, autofix)
}
// countOrphanedRepos count repository where user of owner_id do not exist
func countOrphanedRepos(ctx context.Context) (int64, error) {
return db.CountOrphanedObjects(ctx, "repository", "user", "repository.owner_id=user.id")
}
// deleteOrphanedRepos delete repository where user of owner_id do not exist
func deleteOrphanedRepos(ctx context.Context) (int64, error) {
batchSize := db.MaxBatchInsertSize("repository")
e := db.GetEngine(ctx)
var deleted int64
adminUser := &user_model.User{IsAdmin: true}
for {
select {
case <-ctx.Done():
return deleted, ctx.Err()
default:
var ids []int64
if err := e.Table("`repository`").
Join("LEFT", "`user`", "repository.owner_id=user.id").
Where(builder.IsNull{"`user`.id"}).
Select("`repository`.id").Limit(batchSize).Find(&ids); err != nil {
return deleted, err
}
// if we don't get ids we have deleted them all
if len(ids) == 0 {
return deleted, nil
}
for _, id := range ids {
if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, id, true); err != nil {
return deleted, err
}
deleted++
}
}
}
}
func init() {
Register(&Check{
Title: "Deleted all content related to orphaned repos",
Name: "delete-orphaned-repos",
IsDefault: false,
Run: handleDeleteOrphanedRepos,
Priority: 4,
})
}
+1 -1
View File
@@ -91,7 +91,7 @@ loop:
}
for _, userStopwatches := range usersStopwatches {
apiSWs, err := convert.ToStopWatches(userStopwatches.StopWatches)
apiSWs, err := convert.ToStopWatches(ctx, userStopwatches.StopWatches)
if err != nil {
if !issues_model.IsErrIssueNotExist(err) {
log.Error("Unable to APIFormat stopwatches: %v", err)
+4 -4
View File
@@ -27,7 +27,7 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
assert.Equal(t, "linguist-vendored", attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.Fail(t, "took too long to read an attribute from the list")
assert.FailNow(t, "took too long to read an attribute from the list")
}
// Write a second attribute again
n, err = wr.Write([]byte(testStr))
@@ -41,7 +41,7 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
assert.Equal(t, "linguist-vendored", attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.Fail(t, "took too long to read an attribute from the list")
assert.FailNow(t, "took too long to read an attribute from the list")
}
// Write a partial attribute
@@ -52,14 +52,14 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
select {
case <-wr.ReadAttribute():
assert.Fail(t, "There should not be an attribute ready to read")
assert.FailNow(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
}
_, err = wr.Write([]byte("attribute\x00"))
assert.NoError(t, err)
select {
case <-wr.ReadAttribute():
assert.Fail(t, "There should not be an attribute ready to read")
assert.FailNow(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
}
+21 -29
View File
@@ -116,17 +116,13 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
c.AddArguments("-i")
// add authors if present in search query
if len(opts.Authors) > 0 {
for _, v := range opts.Authors {
c.AddOptionFormat("--author=%s", v)
}
for _, v := range opts.Authors {
c.AddOptionFormat("--author=%s", v)
}
// add committers if present in search query
if len(opts.Committers) > 0 {
for _, v := range opts.Committers {
c.AddOptionFormat("--committer=%s", v)
}
for _, v := range opts.Committers {
c.AddOptionFormat("--committer=%s", v)
}
// add time constraints if present in search query
@@ -150,10 +146,8 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// add remaining keywords from search string
// note this is done only for command created above
if len(opts.Keywords) > 0 {
for _, v := range opts.Keywords {
cmd.AddOptionFormat("--grep=%s", v)
}
for _, v := range opts.Keywords {
cmd.AddOptionFormat("--grep=%s", v)
}
// search for commits matching given constraints and keywords in commit msg
@@ -168,25 +162,23 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// if there are any keywords (ie not committer:, author:, time:)
// then let's iterate over them
if len(opts.Keywords) > 0 {
for _, v := range opts.Keywords {
// ignore anything not matching a valid sha pattern
if IsValidSHAPattern(v) {
// create new git log command with 1 commit limit
hashCmd := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat)
// add previous arguments except for --grep and --all
addCommonSearchArgs(hashCmd)
// add keyword as <commit>
hashCmd.AddDynamicArguments(v)
for _, v := range opts.Keywords {
// ignore anything not matching a valid sha pattern
if IsValidSHAPattern(v) {
// create new git log command with 1 commit limit
hashCmd := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat)
// add previous arguments except for --grep and --all
addCommonSearchArgs(hashCmd)
// add keyword as <commit>
hashCmd.AddDynamicArguments(v)
// search with given constraints for commit matching sha hash of v
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil || bytes.Contains(stdout, hashMatching) {
continue
}
stdout = append(stdout, hashMatching...)
stdout = append(stdout, '\n')
// search with given constraints for commit matching sha hash of v
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil || bytes.Contains(stdout, hashMatching) {
continue
}
stdout = append(stdout, hashMatching...)
stdout = append(stdout, '\n')
}
}
-2
View File
@@ -71,7 +71,6 @@ func TestRepository_GetTag(t *testing.T) {
if lTag == nil {
assert.NotNil(t, lTag)
assert.FailNow(t, "nil lTag: %s", lTagName)
return
}
assert.EqualValues(t, lTagName, lTag.Name)
assert.EqualValues(t, lTagCommitID, lTag.ID.String())
@@ -105,7 +104,6 @@ func TestRepository_GetTag(t *testing.T) {
if aTag == nil {
assert.NotNil(t, aTag)
assert.FailNow(t, "nil aTag: %s", aTagName)
return
}
assert.EqualValues(t, aTagName, aTag.Name)
assert.EqualValues(t, aTagID, aTag.ID.String())
+1 -2
View File
@@ -101,9 +101,8 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string {
return ref.Scheme + "://" + ref.Host + ref.Path
} else if urlPrefixHostname == refHostname || refHostname == sshDomain {
return urlPrefix + path.Clean(path.Join("/", ref.Path))
} else {
return "http://" + refHostname + ref.Path
}
return "http://" + refHostname + ref.Path
}
}
+15 -3
View File
@@ -7,12 +7,17 @@ import (
"context"
"fmt"
"net"
"net/url"
"syscall"
"time"
)
// NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check
func NewDialContext(usage string, allowList, blockList *HostMatchList) func(ctx context.Context, network, addr string) (net.Conn, error) {
return NewDialContextWithProxy(usage, allowList, blockList, nil)
}
func NewDialContextWithProxy(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
// How Go HTTP Client works with redirection:
// transport.RoundTrip URL=http://domain.com, Host=domain.com
// transport.DialContext addrOrHost=domain.com:80
@@ -26,11 +31,18 @@ func NewDialContext(usage string, allowList, blockList *HostMatchList) func(ctx
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
Control: func(network, ipAddr string, c syscall.RawConn) (err error) {
var host string
if host, _, err = net.SplitHostPort(addrOrHost); err != nil {
Control: func(network, ipAddr string, c syscall.RawConn) error {
host, port, err := net.SplitHostPort(addrOrHost)
if err != nil {
return err
}
if proxy != nil {
// Always allow the host of the proxy, but only on the specified port.
if host == proxy.Hostname() && port == proxy.Port() {
return nil
}
}
// in Control func, the addr was already resolved to IP:PORT format, there is no cost to do ResolveTCPAddr here
tcpAddr, err := net.ResolveTCPAddr(network, ipAddr)
if err != nil {
+1 -1
View File
@@ -288,7 +288,7 @@ func populateRepoIndexer(ctx context.Context) {
return
default:
}
ids, err := repo_model.GetUnindexedRepos(repo_model.RepoIndexerTypeCode, maxRepoID, 0, 50)
ids, err := repo_model.GetUnindexedRepos(ctx, repo_model.RepoIndexerTypeCode, maxRepoID, 0, 50)
if err != nil {
log.Error("populateRepoIndexer: %v", err)
return
+2 -4
View File
@@ -96,11 +96,10 @@ func TestBleveIndexAndSearch(t *testing.T) {
idx := bleve.NewIndexer(dir)
_, err := idx.Init(context.Background())
if err != nil {
assert.Fail(t, "Unable to create bleve indexer Error: %v", err)
if idx != nil {
idx.Close()
}
return
assert.FailNow(t, "Unable to create bleve indexer Error: %v", err)
}
defer idx.Close()
@@ -118,11 +117,10 @@ func TestESIndexAndSearch(t *testing.T) {
indexer := elasticsearch.NewIndexer(u, "gitea_codes")
if _, err := indexer.Init(context.Background()); err != nil {
assert.Fail(t, "Unable to init ES indexer Error: %v", err)
if indexer != nil {
indexer.Close()
}
return
assert.FailNow(t, "Unable to init ES indexer Error: %v", err)
}
defer indexer.Close()
-1
View File
@@ -96,7 +96,6 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
}
if len(options.IncludedLabelIDs) == 0 && len(options.IncludedAnyLabelIDs) > 0 {
_ = ctx // issue_model.GetLabelsByIDs should be called with ctx, this line can be removed when it's done.
labels, err := issue_model.GetLabelsByIDs(ctx, options.IncludedAnyLabelIDs, "name")
if err != nil {
return nil, fmt.Errorf("GetLabelsByIDs: %v", err)
+7 -18
View File
@@ -204,12 +204,13 @@ func getIssueIndexerQueueHandler(ctx context.Context) func(items ...*IndexerMeta
func populateIssueIndexer(ctx context.Context) {
ctx, _, finished := process.GetManager().AddTypedContext(ctx, "Service: PopulateIssueIndexer", process.SystemProcessType, true)
defer finished()
if err := PopulateIssueIndexer(ctx, true); err != nil {
ctx = contextWithKeepRetry(ctx) // keep retrying since it's a background task
if err := PopulateIssueIndexer(ctx); err != nil {
log.Error("Issue indexer population failed: %v", err)
}
}
func PopulateIssueIndexer(ctx context.Context, keepRetrying bool) error {
func PopulateIssueIndexer(ctx context.Context) error {
for page := 1; ; page++ {
select {
case <-ctx.Done():
@@ -232,20 +233,8 @@ func PopulateIssueIndexer(ctx context.Context, keepRetrying bool) error {
}
for _, repo := range repos {
for {
select {
case <-ctx.Done():
return fmt.Errorf("shutdown before completion: %w", ctx.Err())
default:
}
if err := updateRepoIndexer(ctx, repo.ID); err != nil {
if keepRetrying && ctx.Err() == nil {
log.Warn("Retry to populate issue indexer for repo %d: %v", repo.ID, err)
continue
}
return fmt.Errorf("populate issue indexer for repo %d: %v", repo.ID, err)
}
break
if err := updateRepoIndexer(ctx, repo.ID); err != nil {
return fmt.Errorf("populate issue indexer for repo %d: %v", repo.ID, err)
}
}
}
@@ -259,8 +248,8 @@ func UpdateRepoIndexer(ctx context.Context, repoID int64) {
}
// UpdateIssueIndexer add/update an issue to the issue indexer
func UpdateIssueIndexer(issueID int64) {
if err := updateIssueIndexer(issueID); err != nil {
func UpdateIssueIndexer(ctx context.Context, issueID int64) {
if err := updateIssueIndexer(ctx, issueID); err != nil {
log.Error("Unable to push issue %d to issue indexer: %v", issueID, err)
}
}
+35 -13
View File
@@ -107,7 +107,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD
NoLabel: len(labels) == 0,
MilestoneID: issue.MilestoneID,
ProjectID: projectID,
ProjectBoardID: issue.ProjectBoardID(),
ProjectBoardID: issue.ProjectBoardID(ctx),
PosterID: issue.PosterID,
AssigneeID: issue.AssigneeID,
MentionIDs: mentionIDs,
@@ -127,15 +127,15 @@ func updateRepoIndexer(ctx context.Context, repoID int64) error {
return fmt.Errorf("issue_model.GetIssueIDsByRepoID: %w", err)
}
for _, id := range ids {
if err := updateIssueIndexer(id); err != nil {
if err := updateIssueIndexer(ctx, id); err != nil {
return err
}
}
return nil
}
func updateIssueIndexer(issueID int64) error {
return pushIssueIndexerQueue(&IndexerMetadata{ID: issueID})
func updateIssueIndexer(ctx context.Context, issueID int64) error {
return pushIssueIndexerQueue(ctx, &IndexerMetadata{ID: issueID})
}
func deleteRepoIssueIndexer(ctx context.Context, repoID int64) error {
@@ -148,13 +148,21 @@ func deleteRepoIssueIndexer(ctx context.Context, repoID int64) error {
if len(ids) == 0 {
return nil
}
return pushIssueIndexerQueue(&IndexerMetadata{
return pushIssueIndexerQueue(ctx, &IndexerMetadata{
IDs: ids,
IsDelete: true,
})
}
func pushIssueIndexerQueue(data *IndexerMetadata) error {
type keepRetryKey struct{}
// contextWithKeepRetry returns a context with a key indicating that the indexer should keep retrying.
// Please note that it's for background tasks only, and it should not be used for user requests, or it may cause blocking.
func contextWithKeepRetry(ctx context.Context) context.Context {
return context.WithValue(ctx, keepRetryKey{}, true)
}
func pushIssueIndexerQueue(ctx context.Context, data *IndexerMetadata) error {
if issueIndexerQueue == nil {
// Some unit tests will trigger indexing, but the queue is not initialized.
// It's OK to ignore it, but log a warning message in case it's not a unit test.
@@ -162,12 +170,26 @@ func pushIssueIndexerQueue(data *IndexerMetadata) error {
return nil
}
err := issueIndexerQueue.Push(data)
if errors.Is(err, queue.ErrAlreadyInQueue) {
return nil
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
err := issueIndexerQueue.Push(data)
if errors.Is(err, queue.ErrAlreadyInQueue) {
return nil
}
if errors.Is(err, context.DeadlineExceeded) { // the queue is full
log.Warn("It seems that issue indexer is slow and the queue is full. Please check the issue indexer or increase the queue size.")
if ctx.Value(keepRetryKey{}) == nil {
return err
}
// It will be better to increase the queue size instead of retrying, but users may ignore the previous warning message.
// However, even it retries, it may still cause index loss when there's a deadline in the context.
log.Debug("Retry to push %+v to issue indexer queue", data)
continue
}
return err
}
if errors.Is(err, context.DeadlineExceeded) {
log.Warn("It seems that issue indexer is slow and the queue is full. Please check the issue indexer or increase the queue size.")
}
return err
}
+1 -1
View File
@@ -68,7 +68,7 @@ func (db *DBIndexer) Index(id int64) error {
}
return err
}
err = repo_model.UpdateLanguageStats(repo, commitID, stats)
err = repo_model.UpdateLanguageStats(ctx, repo, commitID, stats)
if err != nil {
log.Error("Unable to update language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
return err
+5 -3
View File
@@ -4,6 +4,8 @@
package stats
import (
"context"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/graceful"
@@ -28,14 +30,14 @@ func Init() error {
return err
}
go populateRepoIndexer()
go populateRepoIndexer(db.DefaultContext)
return nil
}
// populateRepoIndexer populate the repo indexer with pre-existing data. This
// should only be run when the indexer is created for the first time.
func populateRepoIndexer() {
func populateRepoIndexer(ctx context.Context) {
log.Info("Populating the repo stats indexer with existing repositories")
isShutdown := graceful.GetManager().IsShutdown()
@@ -62,7 +64,7 @@ func populateRepoIndexer() {
return
default:
}
ids, err := repo_model.GetUnindexedRepos(repo_model.RepoIndexerTypeStats, maxRepoID, 0, 50)
ids, err := repo_model.GetUnindexedRepos(ctx, repo_model.RepoIndexerTypeStats, maxRepoID, 0, 50)
if err != nil {
log.Error("populateRepoIndexer: %v", err)
return
+1 -1
View File
@@ -45,7 +45,7 @@ func TestRepoStatsIndex(t *testing.T) {
status, err := repo_model.GetIndexerStatus(db.DefaultContext, repo, repo_model.RepoIndexerTypeStats)
assert.NoError(t, err)
assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.CommitSha)
langs, err := repo_model.GetTopLanguageStats(repo, 5)
langs, err := repo_model.GetTopLanguageStats(db.DefaultContext, repo, 5)
assert.NoError(t, err)
assert.Empty(t, langs)
}
+2 -3
View File
@@ -62,10 +62,9 @@ func TestBasicTransferAdapter(t *testing.T) {
json.NewEncoder(payload).Encode(er)
return &http.Response{StatusCode: http.StatusNotFound, Body: io.NopCloser(payload)}
} else {
t.Errorf("Unknown test case: %s", url)
return nil
}
t.Errorf("Unknown test case: %s", url)
return nil
}
hc := &http.Client{Transport: RoundTripFunc(roundTripHandler)}
+65 -65
View File
@@ -14,7 +14,7 @@ import (
"code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
. "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@@ -37,12 +37,12 @@ func TestMain(m *testing.M) {
}
func TestRender_Commits(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{
buffer, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
RelativePath: ".md",
URLPrefix: TestRepoURL,
URLPrefix: markup.TestRepoURL,
Metas: localMetas,
}, input)
assert.NoError(t, err)
@@ -50,7 +50,7 @@ func TestRender_Commits(t *testing.T) {
}
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
repo := TestRepoURL
repo := markup.TestRepoURL
commit := util.URLJoin(repo, "commit", sha)
tree := util.URLJoin(repo, "tree", sha, "src")
@@ -87,10 +87,10 @@ func TestRender_Commits(t *testing.T) {
}
func TestRender_CrossReferences(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{
buffer, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
RelativePath: "a.md",
URLPrefix: setting.AppSubURL,
@@ -102,43 +102,43 @@ func TestRender_CrossReferences(t *testing.T) {
test(
"gogits/gogs#12345",
`<p><a href="`+util.URLJoin(TestAppURL, "gogits", "gogs", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogits/gogs#12345</a></p>`)
`<p><a href="`+util.URLJoin(markup.TestAppURL, "gogits", "gogs", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogits/gogs#12345</a></p>`)
test(
"go-gitea/gitea#12345",
`<p><a href="`+util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`)
`<p><a href="`+util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`)
test(
"/home/gitea/go-gitea/gitea#12345",
`<p>/home/gitea/go-gitea/gitea#12345</p>`)
test(
util.URLJoin(TestAppURL, "gogitea", "gitea", "issues", "12345"),
`<p><a href="`+util.URLJoin(TestAppURL, "gogitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/gitea#12345</a></p>`)
util.URLJoin(markup.TestAppURL, "gogitea", "gitea", "issues", "12345"),
`<p><a href="`+util.URLJoin(markup.TestAppURL, "gogitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/gitea#12345</a></p>`)
test(
util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345"),
`<p><a href="`+util.URLJoin(TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`)
util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345"),
`<p><a href="`+util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue" rel="nofollow">go-gitea/gitea#12345</a></p>`)
test(
util.URLJoin(TestAppURL, "gogitea", "some-repo-name", "issues", "12345"),
`<p><a href="`+util.URLJoin(TestAppURL, "gogitea", "some-repo-name", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/some-repo-name#12345</a></p>`)
util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345"),
`<p><a href="`+util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/some-repo-name#12345</a></p>`)
}
func TestMisc_IsSameDomain(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
sha := "b6dd6210eaebc915fd5be5579c58cce4da2e2579"
commit := util.URLJoin(TestRepoURL, "commit", sha)
commit := util.URLJoin(markup.TestRepoURL, "commit", sha)
assert.True(t, IsSameDomain(commit))
assert.False(t, IsSameDomain("http://google.com/ncr"))
assert.False(t, IsSameDomain("favicon.ico"))
assert.True(t, markup.IsSameDomain(commit))
assert.False(t, markup.IsSameDomain("http://google.com/ncr"))
assert.False(t, markup.IsSameDomain("favicon.ico"))
}
func TestRender_links(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{
buffer, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
RelativePath: "a.md",
URLPrefix: TestRepoURL,
URLPrefix: markup.TestRepoURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
@@ -147,8 +147,8 @@ func TestRender_links(t *testing.T) {
defaultCustom := setting.Markdown.CustomURLSchemes
setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"}
InitializeSanitizer()
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
markup.InitializeSanitizer()
markup.CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
test(
"https://www.example.com",
@@ -227,18 +227,18 @@ func TestRender_links(t *testing.T) {
// Restore previous settings
setting.Markdown.CustomURLSchemes = defaultCustom
InitializeSanitizer()
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
markup.InitializeSanitizer()
markup.CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
}
func TestRender_email(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
test := func(input, expected string) {
res, err := RenderString(&RenderContext{
res, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
RelativePath: "a.md",
URLPrefix: TestRepoURL,
URLPrefix: markup.TestRepoURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res))
@@ -289,15 +289,15 @@ func TestRender_email(t *testing.T) {
}
func TestRender_emoji(t *testing.T) {
setting.AppURL = TestAppURL
setting.StaticURLPrefix = TestAppURL
setting.AppURL = markup.TestAppURL
setting.StaticURLPrefix = markup.TestAppURL
test := func(input, expected string) {
expected = strings.ReplaceAll(expected, "&", "&amp;")
buffer, err := RenderString(&RenderContext{
buffer, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
RelativePath: "a.md",
URLPrefix: TestRepoURL,
URLPrefix: markup.TestRepoURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
@@ -354,19 +354,19 @@ func TestRender_emoji(t *testing.T) {
}
func TestRender_ShortLinks(t *testing.T) {
setting.AppURL = TestAppURL
tree := util.URLJoin(TestRepoURL, "src", "master")
setting.AppURL = markup.TestAppURL
tree := util.URLJoin(markup.TestRepoURL, "src", "master")
test := func(input, expected, expectedWiki string) {
buffer, err := markdown.RenderString(&RenderContext{
buffer, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: tree,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
buffer, err = markdown.RenderString(&RenderContext{
buffer, err = markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: TestRepoURL,
URLPrefix: markup.TestRepoURL,
Metas: localMetas,
IsWiki: true,
}, input)
@@ -374,7 +374,7 @@ func TestRender_ShortLinks(t *testing.T) {
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
}
rawtree := util.URLJoin(TestRepoURL, "raw", "master")
rawtree := util.URLJoin(markup.TestRepoURL, "raw", "master")
url := util.URLJoin(tree, "Link")
otherURL := util.URLJoin(tree, "Other-Link")
encodedURL := util.URLJoin(tree, "Link%3F")
@@ -382,13 +382,13 @@ func TestRender_ShortLinks(t *testing.T) {
otherImgurl := util.URLJoin(rawtree, "Link+Other.jpg")
encodedImgurl := util.URLJoin(rawtree, "Link+%23.jpg")
notencodedImgurl := util.URLJoin(rawtree, "some", "path", "Link+#.jpg")
urlWiki := util.URLJoin(TestRepoURL, "wiki", "Link")
otherURLWiki := util.URLJoin(TestRepoURL, "wiki", "Other-Link")
encodedURLWiki := util.URLJoin(TestRepoURL, "wiki", "Link%3F")
imgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "Link.jpg")
otherImgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "Link+Other.jpg")
encodedImgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "Link+%23.jpg")
notencodedImgurlWiki := util.URLJoin(TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
urlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Link")
otherURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Other-Link")
encodedURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "Link%3F")
imgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link.jpg")
otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg")
encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg")
notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
favicon := "http://google.com/favicon.ico"
test(
@@ -462,20 +462,20 @@ func TestRender_ShortLinks(t *testing.T) {
}
func TestRender_RelativeImages(t *testing.T) {
setting.AppURL = TestAppURL
tree := util.URLJoin(TestRepoURL, "src", "master")
setting.AppURL = markup.TestAppURL
tree := util.URLJoin(markup.TestRepoURL, "src", "master")
test := func(input, expected, expectedWiki string) {
buffer, err := markdown.RenderString(&RenderContext{
buffer, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: tree,
Metas: localMetas,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
buffer, err = markdown.RenderString(&RenderContext{
buffer, err = markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: TestRepoURL,
URLPrefix: markup.TestRepoURL,
Metas: localMetas,
IsWiki: true,
}, input)
@@ -483,8 +483,8 @@ func TestRender_RelativeImages(t *testing.T) {
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
}
rawwiki := util.URLJoin(TestRepoURL, "wiki", "raw")
mediatree := util.URLJoin(TestRepoURL, "media", "master")
rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw")
mediatree := util.URLJoin(markup.TestRepoURL, "media", "master")
test(
`<img src="Link">`,
@@ -498,7 +498,7 @@ func TestRender_RelativeImages(t *testing.T) {
}
func Test_ParseClusterFuzz(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
localMetas := map[string]string{
"user": "go-gitea",
@@ -508,7 +508,7 @@ func Test_ParseClusterFuzz(t *testing.T) {
data := "<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY "
var res strings.Builder
err := PostProcess(&RenderContext{
err := markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
@@ -519,7 +519,7 @@ func Test_ParseClusterFuzz(t *testing.T) {
data = "<!DOCTYPE html>\n<A><maTH><tr><MN><bodY ÿ><temPlate></template><tH><tr></A><tH><d<bodY "
res.Reset()
err = PostProcess(&RenderContext{
err = markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
@@ -530,7 +530,7 @@ func Test_ParseClusterFuzz(t *testing.T) {
}
func TestPostProcess_RenderDocument(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
localMetas := map[string]string{
"user": "go-gitea",
@@ -540,7 +540,7 @@ func TestPostProcess_RenderDocument(t *testing.T) {
test := func(input, expected string) {
var res strings.Builder
err := PostProcess(&RenderContext{
err := markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
@@ -566,7 +566,7 @@ func TestPostProcess_RenderDocument(t *testing.T) {
}
func TestIssue16020(t *testing.T) {
setting.AppURL = TestAppURL
setting.AppURL = markup.TestAppURL
localMetas := map[string]string{
"user": "go-gitea",
@@ -576,7 +576,7 @@ func TestIssue16020(t *testing.T) {
data := `<img src="data:image/png;base64,i//V"/>`
var res strings.Builder
err := PostProcess(&RenderContext{
err := markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
@@ -593,7 +593,7 @@ func BenchmarkEmojiPostprocess(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var res strings.Builder
err := PostProcess(&RenderContext{
err := markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
@@ -604,7 +604,7 @@ func BenchmarkEmojiPostprocess(b *testing.B) {
func TestFuzz(t *testing.T) {
s := "t/l/issues/8#/../../a"
renderContext := RenderContext{
renderContext := markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com/go-gitea/gitea",
Metas: map[string]string{
@@ -613,7 +613,7 @@ func TestFuzz(t *testing.T) {
},
}
err := PostProcess(&renderContext, strings.NewReader(s), io.Discard)
err := markup.PostProcess(&renderContext, strings.NewReader(s), io.Discard)
assert.NoError(t, err)
}
@@ -622,7 +622,7 @@ func TestIssue18471(t *testing.T) {
data := `http://domain/org/repo/compare/783b039...da951ce`
var res strings.Builder
err := PostProcess(&RenderContext{
err := markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: "https://example.com",
Metas: localMetas,
+18 -18
View File
@@ -13,7 +13,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
. "code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@@ -51,14 +51,14 @@ func TestRender_StandardLinks(t *testing.T) {
setting.AppSubURL = AppSubURL
test := func(input, expected, expectedWiki string) {
buffer, err := RenderString(&markup.RenderContext{
buffer, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: setting.AppSubURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
buffer, err = RenderString(&markup.RenderContext{
buffer, err = markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: setting.AppSubURL,
IsWiki: true,
@@ -82,7 +82,7 @@ func TestRender_Images(t *testing.T) {
setting.AppSubURL = AppSubURL
test := func(input, expected string) {
buffer, err := RenderString(&markup.RenderContext{
buffer, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: setting.AppSubURL,
}, input)
@@ -289,7 +289,7 @@ func TestTotal_RenderWiki(t *testing.T) {
answers := testAnswers(util.URLJoin(AppSubURL, "wiki/"), util.URLJoin(AppSubURL, "wiki", "raw/"))
for i := 0; i < len(sameCases); i++ {
line, err := RenderString(&markup.RenderContext{
line, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: AppSubURL,
Metas: localMetas,
@@ -313,7 +313,7 @@ func TestTotal_RenderWiki(t *testing.T) {
}
for i := 0; i < len(testCases); i += 2 {
line, err := RenderString(&markup.RenderContext{
line, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: AppSubURL,
IsWiki: true,
@@ -330,7 +330,7 @@ func TestTotal_RenderString(t *testing.T) {
answers := testAnswers(util.URLJoin(AppSubURL, "src", "master/"), util.URLJoin(AppSubURL, "raw", "master/"))
for i := 0; i < len(sameCases); i++ {
line, err := RenderString(&markup.RenderContext{
line, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: util.URLJoin(AppSubURL, "src", "master/"),
Metas: localMetas,
@@ -342,7 +342,7 @@ func TestTotal_RenderString(t *testing.T) {
testCases := []string{}
for i := 0; i < len(testCases); i += 2 {
line, err := RenderString(&markup.RenderContext{
line, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: AppSubURL,
}, testCases[i])
@@ -353,17 +353,17 @@ func TestTotal_RenderString(t *testing.T) {
func TestRender_RenderParagraphs(t *testing.T) {
test := func(t *testing.T, str string, cnt int) {
res, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, str)
res, err := markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, str)
assert.NoError(t, err)
assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for unix should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
mac := strings.ReplaceAll(str, "\n", "\r")
res, err = RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, mac)
res, err = markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, mac)
assert.NoError(t, err)
assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for mac should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
dos := strings.ReplaceAll(str, "\n", "\r\n")
res, err = RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, dos)
res, err = markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, dos)
assert.NoError(t, err)
assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for windows should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
}
@@ -391,7 +391,7 @@ func TestMarkdownRenderRaw(t *testing.T) {
for _, testcase := range testcases {
log.Info("Test markdown render error with fuzzy data: %x, the following errors can be recovered", testcase)
_, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, string(testcase))
_, err := markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, string(testcase))
assert.NoError(t, err)
}
}
@@ -403,7 +403,7 @@ func TestRenderSiblingImages_Issue12925(t *testing.T) {
expected := `<p><a href="/image1" target="_blank" rel="nofollow noopener"><img src="/image1" alt="image1"></a><br>
<a href="/image2" target="_blank" rel="nofollow noopener"><img src="/image2" alt="image2"></a></p>
`
res, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
res, err := markdown.RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
assert.NoError(t, err)
assert.Equal(t, expected, res)
}
@@ -412,7 +412,7 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) {
testcase := `[Link with emoji :moon: in text](https://gitea.io)`
expected := `<p><a href="https://gitea.io" rel="nofollow">Link with emoji <span class="emoji" aria-label="waxing gibbous moon">🌔</span> in text</a></p>
`
res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
assert.NoError(t, err)
assert.Equal(t, expected, res)
}
@@ -446,7 +446,7 @@ func TestColorPreview(t *testing.T) {
}
for _, test := range positiveTests {
res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
@@ -466,7 +466,7 @@ func TestColorPreview(t *testing.T) {
}
for _, test := range negativeTests {
res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test)
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test)
assert.NoError(t, err, "Unexpected error in testcase: %q", test)
assert.NotContains(t, res, `<span class="color-preview" style="background-color: `, "Unexpected result in testcase %q", test)
}
@@ -513,7 +513,7 @@ func TestMathBlock(t *testing.T) {
}
for _, test := range testcases {
res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
@@ -551,7 +551,7 @@ foo: bar
}
for _, test := range testcases {
res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
}
+2 -2
View File
@@ -50,7 +50,7 @@ func TestManager_Cancel(t *testing.T) {
select {
case <-ctx.Done():
default:
assert.Fail(t, "Cancel should cancel the provided context")
assert.FailNow(t, "Cancel should cancel the provided context")
}
finished()
@@ -62,7 +62,7 @@ func TestManager_Cancel(t *testing.T) {
select {
case <-ctx.Done():
default:
assert.Fail(t, "Cancel should cancel the provided context")
assert.FailNow(t, "Cancel should cancel the provided context")
}
finished()
}
+1 -1
View File
@@ -46,7 +46,7 @@ CONN_STR = redis://
assert.Equal(t, "default", q.GetName())
assert.Equal(t, "level", q.GetType())
assert.Equal(t, filepath.Join(setting.AppDataPath, "queues/common"), q.baseConfig.DataFullDir)
assert.Equal(t, 100, q.baseConfig.Length)
assert.Equal(t, 100000, q.baseConfig.Length)
assert.Equal(t, 20, q.batchLength)
assert.Equal(t, "", q.baseConfig.ConnStr)
assert.Equal(t, "default_queue", q.baseConfig.QueueFullName)
+1 -8
View File
@@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
@@ -103,12 +102,6 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
assert.EqualValues(t, []string{"readme.md"}, headCommit.Modified)
}
func initGravatarSource(t *testing.T) {
setting.GravatarSource = "https://secure.gravatar.com/avatar"
err := system_model.Init(db.DefaultContext)
assert.NoError(t, err)
}
func TestPushCommits_AvatarLink(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
@@ -132,7 +125,7 @@ func TestPushCommits_AvatarLink(t *testing.T) {
},
}
initGravatarSource(t)
setting.GravatarSource = "https://secure.gravatar.com/avatar"
assert.Equal(t,
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package setting
import (
"sync"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting/config"
)
type PictureStruct struct {
DisableGravatar *config.Value[bool]
EnableFederatedAvatar *config.Value[bool]
}
type ConfigStruct struct {
Picture *PictureStruct
}
var (
defaultConfig *ConfigStruct
defaultConfigOnce sync.Once
)
func initDefaultConfig() {
config.SetCfgSecKeyGetter(&cfgSecKeyGetter{})
defaultConfig = &ConfigStruct{
Picture: &PictureStruct{
DisableGravatar: config.Bool(false, config.CfgSecKey{Sec: "picture", Key: "DISABLE_GRAVATAR"}, "picture.disable_gravatar"),
EnableFederatedAvatar: config.Bool(false, config.CfgSecKey{Sec: "picture", Key: "ENABLE_FEDERATED_AVATAR"}, "picture.enable_federated_avatar"),
},
}
}
func Config() *ConfigStruct {
defaultConfigOnce.Do(initDefaultConfig)
return defaultConfig
}
type cfgSecKeyGetter struct{}
func (c cfgSecKeyGetter) GetValue(sec, key string) (v string, has bool) {
cfgSec, err := CfgProvider.GetSection(sec)
if err != nil {
log.Error("Unable to get config section: %q", sec)
return "", false
}
cfgKey := ConfigSectionKey(cfgSec, key)
if cfgKey == nil {
return "", false
}
return cfgKey.Value(), true
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package config
import (
"context"
"sync"
)
var getterMu sync.RWMutex
type CfgSecKeyGetter interface {
GetValue(sec, key string) (v string, has bool)
}
var cfgSecKeyGetterInternal CfgSecKeyGetter
func SetCfgSecKeyGetter(p CfgSecKeyGetter) {
getterMu.Lock()
cfgSecKeyGetterInternal = p
getterMu.Unlock()
}
func GetCfgSecKeyGetter() CfgSecKeyGetter {
getterMu.RLock()
defer getterMu.RUnlock()
return cfgSecKeyGetterInternal
}
type DynKeyGetter interface {
GetValue(ctx context.Context, key string) (v string, has bool)
GetRevision(ctx context.Context) int
InvalidateCache()
}
var dynKeyGetterInternal DynKeyGetter
func SetDynGetter(p DynKeyGetter) {
getterMu.Lock()
dynKeyGetterInternal = p
getterMu.Unlock()
}
func GetDynGetter() DynKeyGetter {
getterMu.RLock()
defer getterMu.RUnlock()
return dynKeyGetterInternal
}
+81
View File
@@ -0,0 +1,81 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package config
import (
"context"
"strconv"
"sync"
)
type CfgSecKey struct {
Sec, Key string
}
type Value[T any] struct {
mu sync.RWMutex
cfgSecKey CfgSecKey
dynKey string
def, value T
revision int
}
func (value *Value[T]) parse(s string) (v T) {
switch any(v).(type) {
case bool:
b, _ := strconv.ParseBool(s)
return any(b).(T)
default:
panic("unsupported config type, please complete the code")
}
}
func (value *Value[T]) Value(ctx context.Context) (v T) {
dg := GetDynGetter()
if dg == nil {
// this is an edge case: the database is not initialized but the system setting is going to be used
// it should panic to avoid inconsistent config values (from config / system setting) and fix the code
panic("no config dyn value getter")
}
rev := dg.GetRevision(ctx)
// if the revision in database doesn't change, use the last value
value.mu.RLock()
if rev == value.revision {
v = value.value
value.mu.RUnlock()
return v
}
value.mu.RUnlock()
// try to parse the config and cache it
var valStr *string
if dynVal, has := dg.GetValue(ctx, value.dynKey); has {
valStr = &dynVal
} else if cfgVal, has := GetCfgSecKeyGetter().GetValue(value.cfgSecKey.Sec, value.cfgSecKey.Key); has {
valStr = &cfgVal
}
if valStr == nil {
v = value.def
} else {
v = value.parse(*valStr)
}
value.mu.Lock()
value.value = v
value.revision = rev
value.mu.Unlock()
return v
}
func (value *Value[T]) DynKey() string {
return value.dynKey
}
func Bool(def bool, cfgSecKey CfgSecKey, dynKey string) *Value[bool] {
return &Value[bool]{def: def, cfgSecKey: cfgSecKey, dynKey: dynKey}
}
+2 -1
View File
@@ -149,8 +149,9 @@ func EnvironmentToConfig(cfg ConfigProvider, envs []string) (changed bool) {
continue
}
}
key := section.Key(keyName)
key := ConfigSectionKey(section, keyName)
if key == nil {
changed = true
key, err = section.NewKey(keyName, keyValue)
if err != nil {
log.Error("Error creating key: %s in section: %s with value: %s : %v", keyName, sectionName, keyValue, err)
+26
View File
@@ -115,3 +115,29 @@ key = old
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
assert.Equal(t, "value-from-file\n", cfg.Section("sec").Key("key").String())
}
func TestEnvironmentToConfigSubSecKey(t *testing.T) {
// the INI package has a quirk: by default, the keys are inherited.
// when maintaining the keys, the newly added sub key should not be affected by the parent key.
cfg, err := NewConfigProviderFromData(`
[sec]
key = some
`)
assert.NoError(t, err)
changed := EnvironmentToConfig(cfg, []string{"GITEA__sec_0X2E_sub__key=some"})
assert.True(t, changed)
tmpFile := t.TempDir() + "/test-sub-sec-key.ini"
defer os.Remove(tmpFile)
err = cfg.SaveTo(tmpFile)
assert.NoError(t, err)
bs, err := os.ReadFile(tmpFile)
assert.NoError(t, err)
assert.Equal(t, `[sec]
key = some
[sec.sub]
key = some
`, string(bs))
}
+3 -5
View File
@@ -213,11 +213,9 @@ func NewConfigProviderFromFile(file string, extraConfigs ...string) (ConfigProvi
}
}
if len(extraConfigs) > 0 {
for _, s := range extraConfigs {
if err := cfg.Append([]byte(s)); err != nil {
return nil, fmt.Errorf("unable to append more config: %v", err)
}
for _, s := range extraConfigs {
if err := cfg.Append([]byte(s)); err != nil {
return nil, fmt.Errorf("unable to append more config: %v", err)
}
}
+1 -1
View File
@@ -110,7 +110,7 @@ var OAuth2 = struct {
JWTSigningAlgorithm: "RS256",
JWTSigningPrivateKeyFile: "jwt/private.pem",
MaxTokenLength: math.MaxInt16,
DefaultApplications: []string{"git-credential-oauth", "git-credential-manager"},
DefaultApplications: []string{"git-credential-oauth", "git-credential-manager", "tea"},
}
func loadOAuth2From(rootCfg ConfigProvider) {
+1 -1
View File
@@ -30,7 +30,7 @@ func GetQueueSettings(rootCfg ConfigProvider, name string) (QueueSettings, error
queueSettingsDefault := QueueSettings{
Type: "level", // dummy, channel, level, redis
Datadir: "queues/common", // relative to AppDataPath
Length: 100, // queue length before a channel queue will block
Length: 100000, // queue length before a channel queue will block
QueueName: "_queue",
SetName: "_unique",
-2
View File
@@ -19,7 +19,6 @@ var (
SecretKey string
InternalToken string // internal access token
LogInRememberDays int
CookieUserName string
CookieRememberName string
ReverseProxyAuthUser string
ReverseProxyAuthEmail string
@@ -104,7 +103,6 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("security")
InstallLock = HasInstallLock(rootCfg)
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
if SecretKey == "" {
// FIXME: https://github.com/go-gitea/gitea/issues/16832
+2 -2
View File
@@ -76,8 +76,8 @@ var UI = struct {
CodeCommentLines: 4,
ReactionMaxUserNum: 10,
MaxDisplayFileSize: 8388608,
DefaultTheme: `auto`,
Themes: []string{`auto`, `gitea`, `arc-green`},
DefaultTheme: `gitea-auto`,
Themes: []string{`gitea-auto`, `gitea-light`, `gitea-dark`},
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
+11 -3
View File
@@ -16,13 +16,16 @@ const (
CommitStatusError CommitStatusState = "error"
// CommitStatusFailure is for when the CommitStatus is Failure
CommitStatusFailure CommitStatusState = "failure"
// CommitStatusWarning is for when the CommitStatus is Warning
CommitStatusWarning CommitStatusState = "warning"
)
var commitStatusPriorities = map[CommitStatusState]int{
CommitStatusError: 0,
CommitStatusFailure: 1,
CommitStatusPending: 2,
CommitStatusSuccess: 3,
CommitStatusWarning: 2,
CommitStatusPending: 3,
CommitStatusSuccess: 4,
}
func (css CommitStatusState) String() string {
@@ -32,7 +35,7 @@ func (css CommitStatusState) String() string {
// NoBetterThan returns true if this State is no better than the given State
// This function only handles the states defined in CommitStatusPriorities
func (css CommitStatusState) NoBetterThan(css2 CommitStatusState) bool {
// NoBetterThan only handles the 4 states above
// NoBetterThan only handles the 5 states above
if _, exist := commitStatusPriorities[css]; !exist {
return false
}
@@ -63,3 +66,8 @@ func (css CommitStatusState) IsError() bool {
func (css CommitStatusState) IsFailure() bool {
return css == CommitStatusFailure
}
// IsWarning represents if commit status state is warning
func (css CommitStatusState) IsWarning() bool {
return css == CommitStatusWarning
}
+4 -2
View File
@@ -3,10 +3,12 @@
package system
import "context"
// StateStore is the interface to get/set app state items
type StateStore interface {
Get(item StateItem) error
Set(item StateItem) error
Get(ctx context.Context, item StateItem) error
Set(ctx context.Context, item StateItem) error
}
// StateItem provides the name for a state item. the name will be used to generate filenames, etc
+6 -5
View File
@@ -6,6 +6,7 @@ package system
import (
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"github.com/stretchr/testify/assert"
@@ -40,25 +41,25 @@ func TestAppStateDB(t *testing.T) {
as := &DBStore{}
item1 := new(testItem1)
assert.NoError(t, as.Get(item1))
assert.NoError(t, as.Get(db.DefaultContext, item1))
assert.Equal(t, "", item1.Val1)
assert.EqualValues(t, 0, item1.Val2)
item1 = new(testItem1)
item1.Val1 = "a"
item1.Val2 = 2
assert.NoError(t, as.Set(item1))
assert.NoError(t, as.Set(db.DefaultContext, item1))
item2 := new(testItem2)
item2.K = "V"
assert.NoError(t, as.Set(item2))
assert.NoError(t, as.Set(db.DefaultContext, item2))
item1 = new(testItem1)
assert.NoError(t, as.Get(item1))
assert.NoError(t, as.Get(db.DefaultContext, item1))
assert.Equal(t, "a", item1.Val1)
assert.EqualValues(t, 2, item1.Val2)
item2 = new(testItem2)
assert.NoError(t, as.Get(item2))
assert.NoError(t, as.Get(db.DefaultContext, item2))
assert.Equal(t, "V", item2.K)
}
+6 -4
View File
@@ -4,6 +4,8 @@
package system
import (
"context"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/json"
@@ -14,8 +16,8 @@ import (
type DBStore struct{}
// Get reads the state item
func (f *DBStore) Get(item StateItem) error {
content, err := system.GetAppStateContent(item.Name())
func (f *DBStore) Get(ctx context.Context, item StateItem) error {
content, err := system.GetAppStateContent(ctx, item.Name())
if err != nil {
return err
}
@@ -26,10 +28,10 @@ func (f *DBStore) Get(item StateItem) error {
}
// Set saves the state item
func (f *DBStore) Set(item StateItem) error {
func (f *DBStore) Set(ctx context.Context, item StateItem) error {
b, err := json.Marshal(item)
if err != nil {
return err
}
return system.SaveAppStateContent(item.Name(), util.BytesToReadOnlyString(b))
return system.SaveAppStateContent(ctx, item.Name(), util.BytesToReadOnlyString(b))
}
+6 -2
View File
@@ -12,6 +12,7 @@ import (
"strings"
"time"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/markup"
@@ -131,8 +132,11 @@ func NewFuncMap() template.FuncMap {
"DisableImportLocal": func() bool {
return !setting.ImportLocalPaths
},
"DefaultTheme": func() string {
return setting.UI.DefaultTheme
"ThemeName": func(user *user_model.User) string {
if user == nil || user.Theme == "" {
return setting.UI.DefaultTheme
}
return user.Theme
},
"NotificationSettings": func() map[string]any {
return map[string]any{
+1 -2
View File
@@ -210,9 +210,8 @@ func (p *templateErrorPrettier) handleTemplateRenderingError(err error) string {
} else if execErr, ok := err.(texttemplate.ExecError); ok {
layerName := p.assets.GetFileLayerName(execErr.Name + ".tmpl")
return fmt.Sprintf("asset from: %s, %s", layerName, err.Error())
} else {
return err.Error()
}
return err.Error()
}
func HandleTemplateRenderingError(err error) string {
+14 -10
View File
@@ -74,27 +74,31 @@ func ActionIcon(opType activities_model.ActionType) string {
switch opType {
case activities_model.ActionCreateRepo, activities_model.ActionTransferRepo, activities_model.ActionRenameRepo:
return "repo"
case activities_model.ActionCommitRepo, activities_model.ActionPushTag, activities_model.ActionDeleteTag, activities_model.ActionDeleteBranch:
case activities_model.ActionCommitRepo:
return "git-commit"
case activities_model.ActionCreateIssue:
return "issue-opened"
case activities_model.ActionCreatePullRequest:
return "git-pull-request"
case activities_model.ActionCommentIssue, activities_model.ActionCommentPull:
return "comment-discussion"
case activities_model.ActionDeleteBranch:
return "git-branch"
case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest:
return "git-merge"
case activities_model.ActionCloseIssue, activities_model.ActionClosePullRequest:
case activities_model.ActionCreatePullRequest:
return "git-pull-request"
case activities_model.ActionClosePullRequest:
return "git-pull-request-closed"
case activities_model.ActionCreateIssue:
return "issue-opened"
case activities_model.ActionCloseIssue:
return "issue-closed"
case activities_model.ActionReopenIssue, activities_model.ActionReopenPullRequest:
return "issue-reopened"
case activities_model.ActionCommentIssue, activities_model.ActionCommentPull:
return "comment-discussion"
case activities_model.ActionMirrorSyncPush, activities_model.ActionMirrorSyncCreate, activities_model.ActionMirrorSyncDelete:
return "mirror"
case activities_model.ActionApprovePullRequest:
return "check"
case activities_model.ActionRejectPullRequest:
return "diff"
case activities_model.ActionPublishRelease:
return "file-diff"
case activities_model.ActionPublishRelease, activities_model.ActionPushTag, activities_model.ActionDeleteTag:
return "tag"
case activities_model.ActionPullReviewDismissed:
return "x"
+1 -1
View File
@@ -179,7 +179,7 @@ func RenderLabel(ctx context.Context, label *issues_model.Label) template.HTML {
s := fmt.Sprintf("<span class='ui label scope-parent' title='%s'>"+
"<div class='ui label scope-left' style='color: %s !important; background-color: %s !important'>%s</div>"+
"<div class='ui label scope-right' style='color: %s !important; background-color: %s !important''>%s</div>"+
"<div class='ui label scope-right' style='color: %s !important; background-color: %s !important'>%s</div>"+
"</span>",
description,
textColor, scopeColor, scopeText,
+8 -7
View File
@@ -4,6 +4,7 @@
package updatechecker
import (
"context"
"io"
"net/http"
@@ -58,31 +59,31 @@ func GiteaUpdateChecker(httpEndpoint string) error {
return err
}
return UpdateRemoteVersion(respData.Latest.Version)
return UpdateRemoteVersion(req.Context(), respData.Latest.Version)
}
// UpdateRemoteVersion updates the latest available version of Gitea
func UpdateRemoteVersion(version string) (err error) {
return system.AppState.Set(&CheckerState{LatestVersion: version})
func UpdateRemoteVersion(ctx context.Context, version string) (err error) {
return system.AppState.Set(ctx, &CheckerState{LatestVersion: version})
}
// GetRemoteVersion returns the current remote version (or currently installed version if fail to fetch from DB)
func GetRemoteVersion() string {
func GetRemoteVersion(ctx context.Context) string {
item := new(CheckerState)
if err := system.AppState.Get(item); err != nil {
if err := system.AppState.Get(ctx, item); err != nil {
return ""
}
return item.LatestVersion
}
// GetNeedUpdate returns true whether a newer version of Gitea is available
func GetNeedUpdate() bool {
func GetNeedUpdate(ctx context.Context) bool {
curVer, err := version.NewVersion(setting.AppVer)
if err != nil {
// return false to fail silently
return false
}
remoteVerStr := GetRemoteVersion()
remoteVerStr := GetRemoteVersion(ctx)
if remoteVerStr == "" {
// no remote version is known
return false
+1 -2
View File
@@ -40,9 +40,8 @@ func PathJoinRel(elem ...string) string {
return ""
} else if p == "/" {
return "."
} else {
return p[1:]
}
return p[1:]
}
// PathJoinRelX joins the path elements into a single path like PathJoinRel,