From a1f5dd767729e30d07ab42fda80c19f30a72679f Mon Sep 17 00:00:00 2001 From: sillyguodong <33891828+sillyguodong@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:14:35 +0800 Subject: [PATCH 1/9] Make runs-on support variable expression (#29468) As title. Close issue: https://gitea.com/gitea/act_runner/issues/445 Follow: https://gitea.com/gitea/act/pulls/91 Move `getSecretsOfTask` and `getVariablesOfTask` under `models` because of circular dependency issues. --- go.mod | 2 +- go.sum | 4 +- models/actions/variable.go | 33 ++++++++++++ models/secret/secret.go | 39 ++++++++++++++ routers/api/actions/runner/utils.go | 80 +++++------------------------ services/actions/notifier_helper.go | 13 ++++- 6 files changed, 99 insertions(+), 72 deletions(-) diff --git a/go.mod b/go.mod index dfd9a95ea3f5..9b70a191ce57 100644 --- a/go.mod +++ b/go.mod @@ -302,7 +302,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/gitea/act v0.2.51 +replace github.com/nektos/act => gitea.com/gitea/act v0.259.1 replace github.com/gorilla/feeds => github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5 diff --git a/go.sum b/go.sum index 0d8e7dc69979..a44809dde581 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= -gitea.com/gitea/act v0.2.51 h1:gXc/B4OlTciTTzAx9cmNyw04n2SDO7exPjAsR5Idu+c= -gitea.com/gitea/act v0.2.51/go.mod h1:CoaX2053jqBlD6JMgu4d4UgFL/rp2I14Kt5mMqcs0Z0= +gitea.com/gitea/act v0.259.1 h1:8GG1o/xtUHl3qjn5f0h/2FXrT5ubBn05TJOM5ry+FBw= +gitea.com/gitea/act v0.259.1/go.mod h1:UxZWRYqQG2Yj4+4OqfGWW5a3HELwejyWFQyU7F1jUD8= gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669 h1:RUBX+MK/TsDxpHmymaOaydfigEbbzqUnG1OTZU/HAeo= gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc= gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= diff --git a/models/actions/variable.go b/models/actions/variable.go index 12717e0ae461..14ded60fac1d 100644 --- a/models/actions/variable.go +++ b/models/actions/variable.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -82,3 +83,35 @@ func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) }) return count != 0, err } + +func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) { + variables := map[string]string{} + + // Global + globalVariables, err := db.Find[ActionVariable](ctx, FindVariablesOpts{}) + if err != nil { + log.Error("find global variables: %v", err) + return nil, err + } + + // Org / User level + ownerVariables, err := db.Find[ActionVariable](ctx, FindVariablesOpts{OwnerID: run.Repo.OwnerID}) + if err != nil { + log.Error("find variables of org: %d, error: %v", run.Repo.OwnerID, err) + return nil, err + } + + // Repo level + repoVariables, err := db.Find[ActionVariable](ctx, FindVariablesOpts{RepoID: run.RepoID}) + if err != nil { + log.Error("find variables of repo: %d, error: %v", run.RepoID, err) + return nil, err + } + + // Level precedence: Repo > Org / User > Global + for _, v := range append(globalVariables, append(ownerVariables, repoVariables...)...) { + variables[v.Name] = v.Data + } + + return variables, nil +} diff --git a/models/secret/secret.go b/models/secret/secret.go index 41e860d7f664..35bed500b937 100644 --- a/models/secret/secret.go +++ b/models/secret/secret.go @@ -9,7 +9,10 @@ import ( "fmt" "strings" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + actions_module "code.gitea.io/gitea/modules/actions" + "code.gitea.io/gitea/modules/log" secret_module "code.gitea.io/gitea/modules/secret" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -112,3 +115,39 @@ func UpdateSecret(ctx context.Context, secretID int64, data string) error { } return err } + +func GetSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) (map[string]string, error) { + secrets := map[string]string{} + + secrets["GITHUB_TOKEN"] = task.Token + secrets["GITEA_TOKEN"] = task.Token + + if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget { + // ignore secrets for fork pull request, except GITHUB_TOKEN and GITEA_TOKEN which are automatically generated. + // for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch + // see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target + return secrets, nil + } + + ownerSecrets, err := db.Find[Secret](ctx, FindSecretsOptions{OwnerID: task.Job.Run.Repo.OwnerID}) + if err != nil { + log.Error("find secrets of owner %v: %v", task.Job.Run.Repo.OwnerID, err) + return nil, err + } + repoSecrets, err := db.Find[Secret](ctx, FindSecretsOptions{RepoID: task.Job.Run.RepoID}) + if err != nil { + log.Error("find secrets of repo %v: %v", task.Job.Run.RepoID, err) + return nil, err + } + + for _, secret := range append(ownerSecrets, repoSecrets...) { + v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data) + if err != nil { + log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err) + return nil, err + } + secrets[secret.Name] = v + } + + return secrets, nil +} diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go index a7cb31288cab..ff6ec5bd54c6 100644 --- a/routers/api/actions/runner/utils.go +++ b/routers/api/actions/runner/utils.go @@ -15,7 +15,6 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" - secret_module "code.gitea.io/gitea/modules/secret" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/actions" @@ -32,14 +31,24 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv return nil, false, nil } + secrets, err := secret_model.GetSecretsOfTask(ctx, t) + if err != nil { + return nil, false, fmt.Errorf("GetSecretsOfTask: %w", err) + } + + vars, err := actions_model.GetVariablesOfRun(ctx, t.Job.Run) + if err != nil { + return nil, false, fmt.Errorf("GetVariablesOfRun: %w", err) + } + actions.CreateCommitStatus(ctx, t.Job) task := &runnerv1.Task{ Id: t.ID, WorkflowPayload: t.Job.WorkflowPayload, Context: generateTaskContext(t), - Secrets: getSecretsOfTask(ctx, t), - Vars: getVariablesOfTask(ctx, t), + Secrets: secrets, + Vars: vars, } if needs, err := findTaskNeeds(ctx, t); err != nil { @@ -55,71 +64,6 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv return task, true, nil } -func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string { - secrets := map[string]string{} - - secrets["GITHUB_TOKEN"] = task.Token - secrets["GITEA_TOKEN"] = task.Token - - if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget { - // ignore secrets for fork pull request, except GITHUB_TOKEN and GITEA_TOKEN which are automatically generated. - // for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch - // see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target - return secrets - } - - ownerSecrets, err := db.Find[secret_model.Secret](ctx, secret_model.FindSecretsOptions{OwnerID: task.Job.Run.Repo.OwnerID}) - if err != nil { - log.Error("find secrets of owner %v: %v", task.Job.Run.Repo.OwnerID, err) - // go on - } - repoSecrets, err := db.Find[secret_model.Secret](ctx, secret_model.FindSecretsOptions{RepoID: task.Job.Run.RepoID}) - if err != nil { - log.Error("find secrets of repo %v: %v", task.Job.Run.RepoID, err) - // go on - } - - for _, secret := range append(ownerSecrets, repoSecrets...) { - if v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data); err != nil { - log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err) - // go on - } else { - secrets[secret.Name] = v - } - } - - return secrets -} - -func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string { - variables := map[string]string{} - - // Global - globalVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{}) - if err != nil { - log.Error("find global variables: %v", err) - } - - // Org / User level - ownerVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{OwnerID: task.Job.Run.Repo.OwnerID}) - if err != nil { - log.Error("find variables of org: %d, error: %v", task.Job.Run.Repo.OwnerID, err) - } - - // Repo level - repoVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{RepoID: task.Job.Run.RepoID}) - if err != nil { - log.Error("find variables of repo: %d, error: %v", task.Job.Run.RepoID, err) - } - - // Level precedence: Repo > Org / User > Global - for _, v := range append(globalVariables, append(ownerVariables, repoVariables...)...) { - variables[v.Name] = v.Data - } - - return variables -} - func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct { event := map[string]any{} _ = json.Unmarshal([]byte(t.Job.Run.EventPayload), &event) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index b0d848b5add1..d84191dca2b1 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -296,7 +296,18 @@ func handleWorkflows( run.NeedApproval = need } - jobs, err := jobparser.Parse(dwf.Content) + if err := run.LoadAttributes(ctx); err != nil { + log.Error("LoadAttributes: %v", err) + continue + } + + vars, err := actions_model.GetVariablesOfRun(ctx, run) + if err != nil { + log.Error("GetVariablesOfRun: %v", err) + continue + } + + jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars)) if err != nil { log.Error("jobparser.Parse: %v", err) continue From 25b842df261452a29570ba89ffc3a4842d73f68c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 8 Mar 2024 15:30:10 +0800 Subject: [PATCH 2/9] Move get/set default branch from git package to gitrepo package to hide repopath (#29126) --- models/issues/pull.go | 7 +------ modules/git/repo_branch.go | 11 ++--------- modules/gitrepo/branch.go | 17 +++++++++++++++++ routers/api/v1/repo/repo.go | 4 ++-- routers/private/default_branch.go | 3 ++- routers/web/repo/wiki.go | 2 +- services/context/repo.go | 2 +- services/mirror/mirror_pull.go | 2 +- services/repository/adopt.go | 22 +++++++++++----------- services/repository/branch.go | 4 ++-- services/repository/create.go | 7 +------ services/repository/generate.go | 7 +------ services/repository/migrate.go | 9 +-------- services/repository/push.go | 2 +- services/wiki/wiki.go | 16 ++++++++-------- 15 files changed, 52 insertions(+), 63 deletions(-) diff --git a/models/issues/pull.go b/models/issues/pull.go index 7d299eac271b..80b149da5c79 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -901,12 +901,7 @@ func PullRequestCodeOwnersReview(ctx context.Context, pull *Issue, pr *PullReque } defer repo.Close() - branch, err := repo.GetDefaultBranch() - if err != nil { - return err - } - - commit, err := repo.GetBranchCommit(branch) + commit, err := repo.GetBranchCommit(pr.BaseRepo.DefaultBranch) if err != nil { return err } diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 979c5dec9175..552ae2bb8c6c 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -55,15 +55,8 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) { }, nil } -// SetDefaultBranch sets default branch of repository. -func (repo *Repository) SetDefaultBranch(name string) error { - _, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").AddDynamicArguments(BranchPrefix + name).RunStdString(&RunOpts{Dir: repo.Path}) - return err -} - -// GetDefaultBranch gets default branch of repository. -func (repo *Repository) GetDefaultBranch() (string, error) { - stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path}) +func GetDefaultBranch(ctx context.Context, repoPath string) (string, error) { + stdout, _, err := NewCommand(ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repoPath}) if err != nil { return "", err } diff --git a/modules/gitrepo/branch.go b/modules/gitrepo/branch.go index dcaf92668d15..e13a4c82e1c2 100644 --- a/modules/gitrepo/branch.go +++ b/modules/gitrepo/branch.go @@ -30,3 +30,20 @@ func GetBranchCommitID(ctx context.Context, repo Repository, branch string) (str return gitRepo.GetBranchCommitID(branch) } + +// SetDefaultBranch sets default branch of repository. +func SetDefaultBranch(ctx context.Context, repo Repository, name string) error { + _, _, err := git.NewCommand(ctx, "symbolic-ref", "HEAD"). + AddDynamicArguments(git.BranchPrefix + name). + RunStdString(&git.RunOpts{Dir: repoPath(repo)}) + return err +} + +// GetDefaultBranch gets default branch of repository. +func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) { + return git.GetDefaultBranch(ctx, repoPath(repo)) +} + +func GetWikiDefaultBranch(ctx context.Context, repo Repository) (string, error) { + return git.GetDefaultBranch(ctx, wikiPath(repo)) +} diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 5f1af920414f..80504b9c330d 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -720,7 +720,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err if ctx.Repo.GitRepo == nil && !repo.IsEmpty { var err error - ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "Unable to OpenRepository", err) return err @@ -731,7 +731,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err // Default branch only updated if changed and exist or the repository is empty if opts.DefaultBranch != nil && repo.DefaultBranch != *opts.DefaultBranch && (repo.IsEmpty || ctx.Repo.GitRepo.IsBranchExist(*opts.DefaultBranch)) { if !repo.IsEmpty { - if err := ctx.Repo.GitRepo.SetDefaultBranch(*opts.DefaultBranch); err != nil { + if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, *opts.DefaultBranch); err != nil { if !git.IsErrUnsupportedVersion(err) { ctx.Error(http.StatusInternalServerError, "SetDefaultBranch", err) return err diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index 2e323129ef02..33890be6a927 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -9,6 +9,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/private" gitea_context "code.gitea.io/gitea/services/context" ) @@ -20,7 +21,7 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { branch := ctx.Params(":branch") ctx.Repo.Repository.DefaultBranch = branch - if err := ctx.Repo.GitRepo.SetDefaultBranch(ctx.Repo.Repository.DefaultBranch); err != nil { + if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch); err != nil { if !git.IsErrUnsupportedVersion(err) { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err), diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 88b63da88d98..df15f61b173f 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -102,7 +102,7 @@ func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, err commit, errCommit := wikiGitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultWikiBranch) if git.IsErrNotExist(errCommit) { // if the default branch recorded in database is out of sync, then re-sync it - gitRepoDefaultBranch, errBranch := wikiGitRepo.GetDefaultBranch() + gitRepoDefaultBranch, errBranch := gitrepo.GetWikiDefaultBranch(ctx, ctx.Repo.Repository) if errBranch != nil { return wikiGitRepo, nil, errBranch } diff --git a/services/context/repo.go b/services/context/repo.go index 0b15c95e59fb..56e9fada0e93 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -681,7 +681,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch } else { - ctx.Repo.BranchName, _ = gitRepo.GetDefaultBranch() + ctx.Repo.BranchName, _ = gitrepo.GetDefaultBranch(ctx, ctx.Repo.Repository) if ctx.Repo.BranchName == "" { // If it still can't get a default branch, fall back to default branch from setting. // Something might be wrong. Either site admin should fix the repo sync or Gitea should fix a potential bug. diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 3418cf90dfe3..de4a58f27b78 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -593,7 +593,7 @@ func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, gi m.Repo.DefaultBranch = firstName } // Update the git repository default branch - if err := gitRepo.SetDefaultBranch(m.Repo.DefaultBranch); err != nil { + if err := gitrepo.SetDefaultBranch(ctx, m.Repo, m.Repo.DefaultBranch); err != nil { if !git.IsErrUnsupportedVersion(err) { log.Error("Failed to update default branch of underlying git repository %-v. Error: %v", m.Repo, err) desc := fmt.Sprintf("Failed to update default branch of underlying git repository '%s': %v", m.Repo.RepoPath(), err) diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 7ca68776b55a..0ac3c774b7ae 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -127,24 +127,17 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r repo.IsEmpty = false - // Don't bother looking this repo in the context it won't be there - gitRepo, err := gitrepo.OpenRepository(ctx, repo) - if err != nil { - return fmt.Errorf("openRepository: %w", err) - } - defer gitRepo.Close() - if len(defaultBranch) > 0 { repo.DefaultBranch = defaultBranch - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { + if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { return fmt.Errorf("setDefaultBranch: %w", err) } } else { - repo.DefaultBranch, err = gitRepo.GetDefaultBranch() + repo.DefaultBranch, err = gitrepo.GetDefaultBranch(ctx, repo) if err != nil { repo.DefaultBranch = setting.Repository.DefaultBranch - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { + if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { return fmt.Errorf("setDefaultBranch: %w", err) } } @@ -188,7 +181,7 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r repo.DefaultBranch = setting.Repository.DefaultBranch } - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { + if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { return fmt.Errorf("setDefaultBranch: %w", err) } } @@ -197,6 +190,13 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r return fmt.Errorf("updateRepository: %w", err) } + // Don't bother looking this repo in the context it won't be there + gitRepo, err := gitrepo.OpenRepository(ctx, repo) + if err != nil { + return fmt.Errorf("openRepository: %w", err) + } + defer gitRepo.Close() + if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { return fmt.Errorf("SyncReleasesWithTags: %w", err) } diff --git a/services/repository/branch.go b/services/repository/branch.go index 402814fb9a34..763fb966c58b 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -375,7 +375,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m log.Error("CancelRunningJobs: %v", err) } - err2 = gitRepo.SetDefaultBranch(to) + err2 = gitrepo.SetDefaultBranch(ctx, repo, to) if err2 != nil { return err2 } @@ -540,7 +540,7 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR log.Error("CancelRunningJobs: %v", err) } - if err := gitRepo.SetDefaultBranch(newBranchName); err != nil { + if err := gitrepo.SetDefaultBranch(ctx, repo, newBranchName); err != nil { if !git.IsErrUnsupportedVersion(err) { return err } diff --git a/services/repository/create.go b/services/repository/create.go index 8d8c39197dec..971793bcc6e3 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -177,12 +177,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re if len(opts.DefaultBranch) > 0 { repo.DefaultBranch = opts.DefaultBranch - gitRepo, err := gitrepo.OpenRepository(ctx, repo) - if err != nil { - return fmt.Errorf("openRepository: %w", err) - } - defer gitRepo.Close() - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { + if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { return fmt.Errorf("setDefaultBranch: %w", err) } diff --git a/services/repository/generate.go b/services/repository/generate.go index c444b60b2c50..9b09e271ab41 100644 --- a/services/repository/generate.go +++ b/services/repository/generate.go @@ -272,12 +272,7 @@ func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *r repo.DefaultBranch = templateRepo.DefaultBranch } - gitRepo, err := gitrepo.OpenRepository(ctx, repo) - if err != nil { - return fmt.Errorf("openRepository: %w", err) - } - defer gitRepo.Close() - if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { + if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { return fmt.Errorf("setDefaultBranch: %w", err) } if err = UpdateRepository(ctx, repo, false); err != nil { diff --git a/services/repository/migrate.go b/services/repository/migrate.go index aae2ddc1200e..df5cc67ae1cd 100644 --- a/services/repository/migrate.go +++ b/services/repository/migrate.go @@ -57,14 +57,7 @@ func cloneWiki(ctx context.Context, u *user_model.User, opts migration.MigrateOp return "", err } - wikiRepo, err := git.OpenRepository(ctx, wikiPath) - if err != nil { - cleanIncompleteWikiPath() - return "", fmt.Errorf("failed to open wiki repo %q, err: %w", wikiPath, err) - } - defer wikiRepo.Close() - - defaultBranch, err := wikiRepo.GetDefaultBranch() + defaultBranch, err := git.GetDefaultBranch(ctx, wikiPath) if err != nil { cleanIncompleteWikiPath() return "", fmt.Errorf("failed to get wiki repo default branch for %q, err: %w", wikiPath, err) diff --git a/services/repository/push.go b/services/repository/push.go index 89a3127902a5..0aeb4c830b72 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -182,7 +182,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { repo.DefaultBranch = refName repo.IsEmpty = false if repo.DefaultBranch != setting.Repository.DefaultBranch { - if err := gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { + if err := gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { if !git.IsErrUnsupportedVersion(err) { return err } diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 6f1ca120b0a2..1b921a44bdbc 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -370,6 +370,14 @@ func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, n return fmt.Errorf("unable to update database: %w", err) } + oldDefBranch, err := gitrepo.GetWikiDefaultBranch(ctx, repo) + if err != nil { + return fmt.Errorf("unable to get default branch: %w", err) + } + if oldDefBranch == newBranch { + return nil + } + gitRepo, err := gitrepo.OpenWikiRepository(ctx, repo) if errors.Is(err, util.ErrNotExist) { return nil // no git repo on storage, no need to do anything else @@ -378,14 +386,6 @@ func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, n } defer gitRepo.Close() - oldDefBranch, err := gitRepo.GetDefaultBranch() - if err != nil { - return fmt.Errorf("unable to get default branch: %w", err) - } - if oldDefBranch == newBranch { - return nil - } - err = gitRepo.RenameBranch(oldDefBranch, newBranch) if err != nil { return fmt.Errorf("unable to rename default branch: %w", err) From f86e9a03673b70d660a4b7a1e53748757d7a45fa Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 8 Mar 2024 08:57:52 +0100 Subject: [PATCH 3/9] Set user's 24h preference from their current OS locale (#29651) Fixes: https://github.com/go-gitea/gitea/issues/28371 Fixed by using a JS solution that formats according to `lang`, but alters the 24h format setting as per user's locale. This will work for all tooltips: Screenshot 2024-03-07 at 23 03 35 Screenshot 2024-03-07 at 23 03 17 Screenshot 2024-03-07 at 23 14 34 I think there is only one other place in the UI where we render such absolute dates, which is in the actions view and which I've also fixed: Screenshot 2024-03-07 at 23 04 00 --- web_src/js/components/RepoActionView.vue | 4 ++-- web_src/js/modules/tippy.js | 10 +++++++++- web_src/js/utils/time.js | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 97cd05b45bcc..de9625b143ba 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -3,7 +3,7 @@ import {SvgIcon} from '../svg.js'; import ActionRunStatus from './ActionRunStatus.vue'; import {createApp} from 'vue'; import {toggleElem} from '../utils/dom.js'; -import {getCurrentLocale} from '../utils.js'; +import {formatDatetime} from '../utils/time.js'; import {renderAnsi} from '../render/ansi.js'; import {POST, DELETE} from '../modules/fetch.js'; @@ -167,7 +167,7 @@ const sfc = { const logTimeStamp = document.createElement('span'); logTimeStamp.className = 'log-time-stamp'; const date = new Date(parseFloat(line.timestamp * 1000)); - const timeStamp = date.toLocaleString(getCurrentLocale(), {timeZoneName: 'short'}); + const timeStamp = formatDatetime(date); logTimeStamp.textContent = timeStamp; toggleElem(logTimeStamp, this.timeVisible['log-time-stamp']); // for "Show seconds" diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 27f371fd8865..489afc0ae1cf 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -1,5 +1,6 @@ import tippy, {followCursor} from 'tippy.js'; import {isDocumentFragmentOrElementNode} from '../utils/dom.js'; +import {formatDatetime} from '../utils/time.js'; const visibleInstances = new Set(); @@ -93,8 +94,15 @@ function attachTooltip(target, content = null) { } function switchTitleToTooltip(target) { - const title = target.getAttribute('title'); + let title = target.getAttribute('title'); if (title) { + // apply custom formatting to relative-time's tooltips + if (target.tagName.toLowerCase() === 'relative-time') { + const datetime = target.getAttribute('datetime'); + if (datetime) { + title = formatDatetime(new Date(datetime)); + } + } target.setAttribute('data-tooltip-content', title); target.setAttribute('aria-label', title); // keep the attribute, in case there are some other "[title]" selectors diff --git a/web_src/js/utils/time.js b/web_src/js/utils/time.js index 3284e893e137..1848792c984c 100644 --- a/web_src/js/utils/time.js +++ b/web_src/js/utils/time.js @@ -1,4 +1,5 @@ import dayjs from 'dayjs'; +import {getCurrentLocale} from '../utils.js'; // Returns an array of millisecond-timestamps of start-of-week days (Sundays) export function startDaysBetween(startDate, endDate) { @@ -44,3 +45,23 @@ export function fillEmptyStartDaysWithZeroes(startDays, data) { return Object.values(result); } + +let dateFormat; + +// format a Date object to document's locale, but with 24h format from user's current locale because this +// option is a personal preference of the user, not something that the document's locale should dictate. +export function formatDatetime(date) { + if (!dateFormat) { + // TODO: replace `hour12` with `Intl.Locale.prototype.getHourCycles` once there is broad browser support + dateFormat = new Intl.DateTimeFormat(getCurrentLocale(), { + day: 'numeric', + month: 'short', + year: 'numeric', + hour: 'numeric', + hour12: !Number.isInteger(Number(new Intl.DateTimeFormat([], {hour: 'numeric'}).format())), + minute: '2-digit', + timeZoneName: 'short', + }); + } + return dateFormat.format(date); +} From 9dc8a6336edddca0f3f90392bbc398f4ceaeaf13 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 8 Mar 2024 17:44:50 +0900 Subject: [PATCH 4/9] Fix incorrect rendering csv file when file size is larger than UI.CSV.MaxFileSize (#29653) Fix #29506 --- modules/markup/csv/csv.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index 7af34a6cbc2d..12458e954ade 100644 --- a/modules/markup/csv/csv.go +++ b/modules/markup/csv/csv.go @@ -93,8 +93,10 @@ func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Wri if _, err := tmpBlock.WriteString(html.EscapeString(string(rawBytes))); err != nil { return err } - _, err = tmpBlock.WriteString("") - return err + if _, err := tmpBlock.WriteString(""); err != nil { + return err + } + return tmpBlock.Flush() } rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, bytes.NewReader(rawBytes)) From b5c418f271963f8de0b8324305ea74cde7d3f3ab Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Fri, 8 Mar 2024 11:30:41 +0200 Subject: [PATCH 5/9] Don't use `
` in alert block (#29650) - Follows https://github.com/go-gitea/gitea/pull/29121 When I implemented alert blocks I was always testing the markdown in issue comments. I used `
` for line breaks and it looked good. I have since learned that the markdown on README files doesn't allow these tags. So a comment with ```md > [!NOTE] > If you're interested in using our APIs, we have experimental support with [documentation](https://try.gitea.io/api/swagger). ``` looked like this in a comment ![image](https://github.com/go-gitea/gitea/assets/20454870/96b1de01-2c87-4d4f-83dd-98192b83e9d0) but looked like this in a README ![image](https://github.com/go-gitea/gitea/assets/20454870/474b636d-dd7a-4b7f-ba27-643803c71aa3) So I changed how we render the alert block by having the alert itself have a dedicated paragraph, so line breaks happen naturally between paragraphs. # Before ![image](https://github.com/go-gitea/gitea/assets/20454870/474b636d-dd7a-4b7f-ba27-643803c71aa3) ![image](https://github.com/go-gitea/gitea/assets/20454870/167a8d37-9a44-4479-9340-5dc80347b595) # After ![image](https://github.com/go-gitea/gitea/assets/20454870/2f99fec0-98ff-4ba8-97fe-b4567041ae79) ![image](https://github.com/go-gitea/gitea/assets/20454870/ffdeae11-fb06-4d00-b497-eae135f0d7ad) --------- Signed-off-by: Yarden Shoham Co-authored-by: silverwind --- modules/markup/markdown/goldmark.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index c4b23e66fc51..67817ce27bf3 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -219,21 +219,18 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa v.SetAttributeString("class", []byte("gt-py-3 attention attention-"+attentionType)) // create an emphasis to make it bold + attentionParagraph := ast.NewParagraph() emphasis := ast.NewEmphasis(2) emphasis.SetAttributeString("class", []byte("attention-"+attentionType)) - firstParagraph.InsertBefore(firstParagraph, firstTextNode, emphasis) // capitalize first letter attentionText := ast.NewString([]byte(strings.ToUpper(string(attentionType[0])) + attentionType[1:])) - // replace the ![TYPE] with icon+Type + // replace the ![TYPE] with a dedicated paragraph of icon+Type emphasis.AppendChild(emphasis, attentionText) - for i := 0; i < 2; i++ { - lineBreak := ast.NewText() - lineBreak.SetSoftLineBreak(true) - firstParagraph.InsertAfter(firstParagraph, emphasis, lineBreak) - } - firstParagraph.InsertBefore(firstParagraph, emphasis, NewAttention(attentionType)) + attentionParagraph.AppendChild(attentionParagraph, NewAttention(attentionType)) + attentionParagraph.AppendChild(attentionParagraph, emphasis) + firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph) firstParagraph.RemoveChild(firstParagraph, firstTextNode) firstParagraph.RemoveChild(firstParagraph, secondTextNode) firstParagraph.RemoveChild(firstParagraph, thirdTextNode) From 114bb505a3b0819db683d4b586e950df6a17bff8 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 8 Mar 2024 10:42:12 +0100 Subject: [PATCH 6/9] Style fomantic grey labels (#29458) Fomantic grey labels in the dashboard repo lists were showing original fomantic colors, fixed that. Also slightly tweaked the light theme colors so it uses same opacity values as dark theme. Screenshot 2024-03-07 at 21 06 23 Screenshot 2024-03-07 at 21 06 00 --- web_src/css/base.css | 4 +++- web_src/css/themes/theme-gitea-light.css | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/web_src/css/base.css b/web_src/css/base.css index 77359b36e500..3db9cd894ca8 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1448,7 +1448,9 @@ strong.attention-caution, span.attention-caution { } .ui.label, -.ui.menu .item > .label { +.ui.menu .item > .label, +.ui.grey.labels .label, +.ui.ui.ui.grey.label { background: var(--color-label-bg); color: var(--color-label-text); } diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 5137e0774c29..fbe2458ed6d3 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -228,9 +228,9 @@ --color-nav-hover-bg: #ebebeb; --color-nav-text: var(--color-text); --color-label-text: var(--color-text); - --color-label-bg: #cacaca5b; - --color-label-hover-bg: #cacacaa0; - --color-label-active-bg: #cacacaff; + --color-label-bg: #9d9d9d4b; + --color-label-hover-bg: #9d9d9da0; + --color-label-active-bg: #9d9d9dff; --color-accent: var(--color-primary-light-1); --color-small-accent: var(--color-primary-light-6); --color-active-line: #fffbdd; From 886e90aa82521d2c2ae17d3e177c056ae32e4aa6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 8 Mar 2024 10:47:32 +0100 Subject: [PATCH 7/9] Don't show AbortErrors on logout (#29639) When logging out of Gitea, a error toast can be seen for a split second. I don't know why or how it happens but I found it it's an `AbortError` (related to [AbortController#abort](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort)), so let's hide it. --- web_src/js/features/common-global.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 211253ef9aa2..ee4ade1f0474 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -105,8 +105,10 @@ async function fetchActionDoRequest(actionElem, url, opt) { showErrorToast(`server error: ${resp.status}`); } } catch (e) { - console.error('error when doRequest', e); - showErrorToast(`${i18n.network_error} ${e}`); + if (e.name !== 'AbortError') { + console.error('error when doRequest', e); + showErrorToast(`${i18n.network_error} ${e}`); + } } actionElem.classList.remove('is-loading', 'small-loading-icon'); } From f219ea8d0e0eccd74c786202a4ddb2784a0175ad Mon Sep 17 00:00:00 2001 From: DC <106393991+DanielMatiasCarvalho@users.noreply.github.com> Date: Fri, 8 Mar 2024 09:53:01 +0000 Subject: [PATCH 8/9] Fix user-defined markup links targets (#29305) This seeks to fix the bug reported on issue #29196. Cause: ID's with custom characters (- , _ , etc.), were not linking correctly in the Markdown file when rendered in the browser because the ID in the respective destinies would be different than the one in anchor, while for IDs with only letters, the ID would be the same. Fix: It was suggested that to fix this bug, it should more or less like GitHub does it. While in gitea the anchors would be put in HTML like this: ```

Review

Staging

Development

Testing

Unit-tests

``` In GitHub, the same anchor's href properties would be the same without "user-content-" trailing behind. So my code made sure to change those anchors, so it would not include "user-content-" and then add respective Event Listeners so it would scroll into the supposed places. Fixes: #29196 --------- Co-authored-by: silverwind --- web_src/js/markup/anchors.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/web_src/js/markup/anchors.js b/web_src/js/markup/anchors.js index 53dfa2980c0a..03934ea215fa 100644 --- a/web_src/js/markup/anchors.js +++ b/web_src/js/markup/anchors.js @@ -2,6 +2,7 @@ import {svg} from '../svg.js'; const headingSelector = '.markup h1, .markup h2, .markup h3, .markup h4, .markup h5, .markup h6'; +// scroll to anchor while respecting the `user-content` prefix that exists on the target function scrollToAnchor(hash, initial) { // abort if the browser has already scrolled to another anchor during page load if (initial && document.querySelector(':target')) return; @@ -19,6 +20,7 @@ function scrollToAnchor(hash, initial) { export function initMarkupAnchors() { if (!document.querySelector('.markup')) return; + // create link icons for markup headings, the resulting link href will remove `user-content-` for (const heading of document.querySelectorAll(headingSelector)) { const originalId = heading.id.replace(/^user-content-/, ''); const a = document.createElement('a'); @@ -31,5 +33,18 @@ export function initMarkupAnchors() { heading.prepend(a); } + // handle user-defined `name` anchors like `[Link](#link)` linking to `Link` + for (const a of document.querySelectorAll('.markup a[href^="#"]')) { + const href = a.getAttribute('href'); + if (!href.startsWith('#user-content-')) continue; + const originalId = href.replace(/^#user-content-/, ''); + a.setAttribute('href', `#${encodeURIComponent(originalId)}`); + if (document.getElementsByName(originalId).length !== 1) { + a.addEventListener('click', (e) => { + scrollToAnchor(e.currentTarget.getAttribute('href'), false); + }); + } + } + scrollToAnchor(window.location.hash, true); } From 930bae2300be1c62a56d6f019e519b6752d41ad1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 8 Mar 2024 18:21:24 +0800 Subject: [PATCH 9/9] Add cache for branch divergence on branch list page (#29577) The branch page for blender project will take 6s because calculating divergence is very slow. This PR will add a cache for the branch divergence calculation. So when the second visit the branch list, it will take only less 200ms. --- services/repository/branch.go | 55 +++++++++++++++++++++++++++++++---- services/repository/push.go | 5 ++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index 763fb966c58b..8d8cfa2d19d8 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -16,9 +16,11 @@ import ( 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/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/queue" @@ -99,7 +101,6 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) } - branches = append(branches, branch) } @@ -109,10 +110,44 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git if err != nil { return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) } - return defaultBranch, branches, totalNumOfBranches, nil } +func getDivergenceCacheKey(repoID int64, branchName string) string { + return fmt.Sprintf("%d-%s", repoID, branchName) +} + +// getDivergenceFromCache gets the divergence from cache +func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject, bool) { + data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName)) + res := git.DivergeObject{ + Ahead: -1, + Behind: -1, + } + s, ok := data.([]byte) + if !ok || len(s) == 0 { + return &res, false + } + + if err := json.Unmarshal(s, &res); err != nil { + log.Error("json.UnMarshal failed: %v", err) + return &res, false + } + return &res, true +} + +func putDivergenceFromCache(repoID int64, branchName string, divergence *git.DivergeObject) error { + bs, err := json.Marshal(divergence) + if err != nil { + return err + } + return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60) +} + +func DelDivergenceFromCache(repoID int64, branchName string) error { + return cache.GetCache().Delete(getDivergenceCacheKey(repoID, branchName)) +} + func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *git_model.Branch, protectedBranches *git_model.ProtectedBranchRules, repoIDToRepo map[int64]*repo_model.Repository, repoIDToGitRepo map[int64]*git.Repository, @@ -130,10 +165,18 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g // it's not default branch if repo.DefaultBranch != dbBranch.Name && !dbBranch.IsDeleted { - var err error - divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) - if err != nil { - log.Error("CountDivergingCommits: %v", err) + var cached bool + divergence, cached = getDivergenceFromCache(repo.ID, dbBranch.Name) + if !cached { + var err error + divergence, err = files_service.CountDivergingCommits(ctx, repo, git.BranchPrefix+branchName) + if err != nil { + log.Error("CountDivergingCommits: %v", err) + } else { + if err = putDivergenceFromCache(repo.ID, dbBranch.Name, divergence); err != nil { + log.Error("putDivergenceFromCache: %v", err) + } + } } } diff --git a/services/repository/push.go b/services/repository/push.go index 0aeb4c830b72..39843249a53a 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -220,6 +220,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } + // delete cache for divergence + if err := DelDivergenceFromCache(repo.ID, branch); err != nil { + log.Error("DelDivergenceFromCache: %v", err) + } + commits := repo_module.GitToPushCommits(l) commits.HeadCommit = repo_module.CommitToPushCommit(newCommit)