From 0b1a42ce0f7f8e22d7905bde803d60444c9a9f0b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 31 Jan 2024 22:32:17 +0900 Subject: [PATCH 01/11] Fix doc img path in profile readme (#28994) https://gitea.com/gitea/gitea-docusaurus/actions/runs/1007/jobs/0#jobstep-9-25 --- docs/content/usage/profile-readme.en-us.md | 2 +- .../images}/usage/profile-readme.png | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{content => static/images}/usage/profile-readme.png (100%) diff --git a/docs/content/usage/profile-readme.en-us.md b/docs/content/usage/profile-readme.en-us.md index fe42fa2723..316a735a1c 100644 --- a/docs/content/usage/profile-readme.en-us.md +++ b/docs/content/usage/profile-readme.en-us.md @@ -22,4 +22,4 @@ Making the `.profile` repository private will hide the Profile README. Example of user with `.profile/README.md`: -![profile readme screenshot](./profile-readme.png) +![profile readme screenshot](/images/usage/profile-readme.png) diff --git a/docs/content/usage/profile-readme.png b/docs/static/images/usage/profile-readme.png similarity index 100% rename from docs/content/usage/profile-readme.png rename to docs/static/images/usage/profile-readme.png From adc3598a755b43e3911266d7fa575c121e16613d Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Wed, 31 Jan 2024 22:55:12 +0800 Subject: [PATCH 02/11] Fix an actions schedule bug (#28942) In #28691, schedule plans will be deleted when a repo's actions unit is disabled. But when the unit is enabled, the schedule plans won't be created again. This PR fixes the bug. The schedule plans will be created again when the actions unit is re-enabled --- modules/actions/workflows.go | 35 +++++++++++++++++++++++++++++ routers/api/v1/repo/wiki.go | 4 ++-- services/actions/notifier_helper.go | 32 ++++++++++++++++++++++++++ services/actions/schedule_tasks.go | 12 ++++++++-- services/convert/wiki.go | 15 ------------- services/repository/setting.go | 10 +++++++++ services/wiki/wiki_path.go | 15 +++++++++++++ 7 files changed, 104 insertions(+), 19 deletions(-) diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index cbc7e011d1..a883f4181b 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -146,6 +146,41 @@ func DetectWorkflows( return workflows, schedules, nil } +func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) { + entries, err := ListWorkflows(commit) + if err != nil { + return nil, err + } + + wfs := make([]*DetectedWorkflow, 0, len(entries)) + for _, entry := range entries { + content, err := GetContentFromEntry(entry) + if err != nil { + return nil, err + } + + // one workflow may have multiple events + events, err := GetEventsFromContent(content) + if err != nil { + log.Warn("ignore invalid workflow %q: %v", entry.Name(), err) + continue + } + for _, evt := range events { + if evt.IsSchedule() { + log.Trace("detect scheduled workflow: %q", entry.Name()) + dwf := &DetectedWorkflow{ + EntryName: entry.Name(), + TriggerEvent: evt, + Content: content, + } + wfs = append(wfs, dwf) + } + } + } + + return wfs, nil +} + func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool { if !canGithubEventMatch(evt.Name, triggedEvent) { return false diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index ba3e978a83..4f27500496 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -203,7 +203,7 @@ func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.Wi } return &api.WikiPage{ - WikiPageMetaData: convert.ToWikiPageMetaData(wikiName, lastCommit, ctx.Repo.Repository), + WikiPageMetaData: wiki_service.ToWikiPageMetaData(wikiName, lastCommit, ctx.Repo.Repository), ContentBase64: content, CommitCount: commitsCount, Sidebar: sidebarContent, @@ -333,7 +333,7 @@ func ListWikiPages(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "WikiFilenameToName", err) return } - pages = append(pages, convert.ToWikiPageMetaData(wikiName, c, ctx.Repo.Repository)) + pages = append(pages, wiki_service.ToWikiPageMetaData(wikiName, c, ctx.Repo.Repository)) } ctx.SetTotalCountHeader(int64(len(entries))) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 9900de3d2e..77173e58a3 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -474,3 +474,35 @@ func handleSchedules( return actions_model.CreateScheduleTask(ctx, crons) } + +// DetectAndHandleSchedules detects the schedule workflows on the default branch and create schedule tasks +func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) error { + gitRepo, err := gitrepo.OpenRepository(context.Background(), repo) + if err != nil { + return fmt.Errorf("git.OpenRepository: %w", err) + } + defer gitRepo.Close() + + // Only detect schedule workflows on the default branch + commit, err := gitRepo.GetCommit(repo.DefaultBranch) + if err != nil { + return fmt.Errorf("gitRepo.GetCommit: %w", err) + } + scheduleWorkflows, err := actions_module.DetectScheduledWorkflows(gitRepo, commit) + if err != nil { + return fmt.Errorf("detect schedule workflows: %w", err) + } + if len(scheduleWorkflows) == 0 { + return nil + } + + // We need a notifyInput to call handleSchedules + // Here we use the commit author as the Doer of the notifyInput + commitUser, err := user_model.GetUserByEmail(ctx, commit.Author.Email) + if err != nil { + return fmt.Errorf("get user by email: %w", err) + } + notifyInput := newNotifyInput(repo, commitUser, webhook_module.HookEventSchedule) + + return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) +} diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go index e7aa4a39ac..79dd84e0cc 100644 --- a/services/actions/schedule_tasks.go +++ b/services/actions/schedule_tasks.go @@ -10,6 +10,7 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" @@ -65,8 +66,15 @@ func startTasks(ctx context.Context) error { } } - cfg := row.Repo.MustGetUnit(ctx, unit.TypeActions).ActionsConfig() - if cfg.IsWorkflowDisabled(row.Schedule.WorkflowID) { + cfg, err := row.Repo.GetUnit(ctx, unit.TypeActions) + if err != nil { + if repo_model.IsErrUnitTypeNotExist(err) { + // Skip the actions unit of this repo is disabled. + continue + } + return fmt.Errorf("GetUnit: %w", err) + } + if cfg.ActionsConfig().IsWorkflowDisabled(row.Schedule.WorkflowID) { continue } diff --git a/services/convert/wiki.go b/services/convert/wiki.go index 1f04843483..767bfdb88d 100644 --- a/services/convert/wiki.go +++ b/services/convert/wiki.go @@ -6,11 +6,8 @@ package convert import ( "time" - repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - wiki_service "code.gitea.io/gitea/services/wiki" ) // ToWikiCommit convert a git commit into a WikiCommit @@ -46,15 +43,3 @@ func ToWikiCommitList(commits []*git.Commit, total int64) *api.WikiCommitList { Count: total, } } - -// ToWikiPageMetaData converts meta information to a WikiPageMetaData -func ToWikiPageMetaData(wikiName wiki_service.WebPath, lastCommit *git.Commit, repo *repo_model.Repository) *api.WikiPageMetaData { - subURL := string(wikiName) - _, title := wiki_service.WebPathToUserTitle(wikiName) - return &api.WikiPageMetaData{ - Title: title, - HTMLURL: util.URLJoin(repo.HTMLURL(), "wiki", subURL), - SubURL: subURL, - LastCommit: ToWikiCommit(lastCommit), - } -} diff --git a/services/repository/setting.go b/services/repository/setting.go index 6496ac4014..b82f24271e 100644 --- a/services/repository/setting.go +++ b/services/repository/setting.go @@ -12,6 +12,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/log" + actions_service "code.gitea.io/gitea/services/actions" ) // UpdateRepositoryUnits updates a repository's units @@ -33,6 +34,15 @@ func UpdateRepositoryUnits(ctx context.Context, repo *repo_model.Repository, uni } } + for _, u := range units { + if u.Type == unit.TypeActions { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules: %v", err) + } + break + } + } + if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil { return err } diff --git a/services/wiki/wiki_path.go b/services/wiki/wiki_path.go index e51d6c630c..74c7064043 100644 --- a/services/wiki/wiki_path.go +++ b/services/wiki/wiki_path.go @@ -9,7 +9,10 @@ import ( "strings" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/convert" ) // To define the wiki related concepts: @@ -155,3 +158,15 @@ func UserTitleToWebPath(base, title string) WebPath { } return WebPath(title) } + +// ToWikiPageMetaData converts meta information to a WikiPageMetaData +func ToWikiPageMetaData(wikiName WebPath, lastCommit *git.Commit, repo *repo_model.Repository) *api.WikiPageMetaData { + subURL := string(wikiName) + _, title := WebPathToUserTitle(wikiName) + return &api.WikiPageMetaData{ + Title: title, + HTMLURL: util.URLJoin(repo.HTMLURL(), "wiki", subURL), + SubURL: subURL, + LastCommit: convert.ToWikiCommit(lastCommit), + } +} From 3b50dd95cefc003d72b5ef5b77c28e8a4d30795c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 31 Jan 2024 23:23:22 +0800 Subject: [PATCH 03/11] Some refactor for git http (#28995) # Purpose This PR makes git http related functions use the same `context.Context` so they can be maintained easier. --- routers/web/repo/githttp.go | 185 +++++++++++++++++------------------- 1 file changed, 85 insertions(+), 100 deletions(-) diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 6d3dd5a3fe..f52abbfb02 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -11,7 +11,7 @@ import ( "fmt" "net/http" "os" - "path" + "path/filepath" "regexp" "strconv" "strings" @@ -90,11 +90,10 @@ func httpBase(ctx *context.Context) *serviceHandler { isWiki := false unitType := unit.TypeCode - var wikiRepoName string + if strings.HasSuffix(reponame, ".wiki") { isWiki = true unitType = unit.TypeWiki - wikiRepoName = reponame reponame = reponame[:len(reponame)-5] } @@ -107,16 +106,16 @@ func httpBase(ctx *context.Context) *serviceHandler { repoExist := true repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, reponame) if err != nil { - if repo_model.IsErrRepoNotExist(err) { - if redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, reponame); err == nil { - context.RedirectToRepo(ctx.Base, redirectRepoID) - return nil - } - repoExist = false - } else { + if !repo_model.IsErrRepoNotExist(err) { ctx.ServerError("GetRepositoryByName", err) return nil } + + if redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, reponame); err == nil { + context.RedirectToRepo(ctx.Base, redirectRepoID) + return nil + } + repoExist = false } // Don't allow pushing if the repo is archived @@ -292,22 +291,9 @@ func httpBase(ctx *context.Context) *serviceHandler { environ = append(environ, repo_module.EnvRepoID+fmt.Sprintf("=%d", repo.ID)) - w := ctx.Resp - r := ctx.Req - cfg := &serviceConfig{ - UploadPack: true, - ReceivePack: true, - Env: environ, - } + ctx.Req.URL.Path = strings.ToLower(ctx.Req.URL.Path) // blue: In case some repo name has upper case name - r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name - - dir := repo_model.RepoPath(username, reponame) - if isWiki { - dir = repo_model.RepoPath(username, wikiRepoName) - } - - return &serviceHandler{cfg, w, r, dir, cfg.Env} + return &serviceHandler{repo, isWiki, environ} } var ( @@ -352,32 +338,31 @@ func dummyInfoRefs(ctx *context.Context) { _, _ = ctx.Write(infoRefsCache) } -type serviceConfig struct { - UploadPack bool - ReceivePack bool - Env []string -} - type serviceHandler struct { - cfg *serviceConfig - w http.ResponseWriter - r *http.Request - dir string + repo *repo_model.Repository + isWiki bool environ []string } -func (h *serviceHandler) setHeaderNoCache() { - h.w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT") - h.w.Header().Set("Pragma", "no-cache") - h.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") +func (h *serviceHandler) getRepoDir() string { + if h.isWiki { + return h.repo.WikiPath() + } + return h.repo.RepoPath() } -func (h *serviceHandler) setHeaderCacheForever() { +func setHeaderNoCache(ctx *context.Context) { + ctx.Resp.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT") + ctx.Resp.Header().Set("Pragma", "no-cache") + ctx.Resp.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") +} + +func setHeaderCacheForever(ctx *context.Context) { now := time.Now().Unix() expires := now + 31536000 - h.w.Header().Set("Date", fmt.Sprintf("%d", now)) - h.w.Header().Set("Expires", fmt.Sprintf("%d", expires)) - h.w.Header().Set("Cache-Control", "public, max-age=31536000") + ctx.Resp.Header().Set("Date", fmt.Sprintf("%d", now)) + ctx.Resp.Header().Set("Expires", fmt.Sprintf("%d", expires)) + ctx.Resp.Header().Set("Cache-Control", "public, max-age=31536000") } func containsParentDirectorySeparator(v string) bool { @@ -394,71 +379,71 @@ func containsParentDirectorySeparator(v string) bool { func isSlashRune(r rune) bool { return r == '/' || r == '\\' } -func (h *serviceHandler) sendFile(contentType, file string) { +func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string) { if containsParentDirectorySeparator(file) { log.Error("request file path contains invalid path: %v", file) - h.w.WriteHeader(http.StatusBadRequest) + ctx.Resp.WriteHeader(http.StatusBadRequest) return } - reqFile := path.Join(h.dir, file) + reqFile := filepath.Join(h.getRepoDir(), file) fi, err := os.Stat(reqFile) if os.IsNotExist(err) { - h.w.WriteHeader(http.StatusNotFound) + ctx.Resp.WriteHeader(http.StatusNotFound) return } - h.w.Header().Set("Content-Type", contentType) - h.w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size())) - h.w.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat)) - http.ServeFile(h.w, h.r, reqFile) + ctx.Resp.Header().Set("Content-Type", contentType) + ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size())) + ctx.Resp.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat)) + http.ServeFile(ctx.Resp, ctx.Req, reqFile) } // one or more key=value pairs separated by colons var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`) -func prepareGitCmdWithAllowedService(service string, h *serviceHandler) (*git.Command, error) { - if service == "receive-pack" && h.cfg.ReceivePack { - return git.NewCommand(h.r.Context(), "receive-pack"), nil +func prepareGitCmdWithAllowedService(ctx *context.Context, service string) (*git.Command, error) { + if service == "receive-pack" { + return git.NewCommand(ctx, "receive-pack"), nil } - if service == "upload-pack" && h.cfg.UploadPack { - return git.NewCommand(h.r.Context(), "upload-pack"), nil + if service == "upload-pack" { + return git.NewCommand(ctx, "upload-pack"), nil } return nil, fmt.Errorf("service %q is not allowed", service) } -func serviceRPC(h *serviceHandler, service string) { +func serviceRPC(ctx *context.Context, h *serviceHandler, service string) { defer func() { - if err := h.r.Body.Close(); err != nil { + if err := ctx.Req.Body.Close(); err != nil { log.Error("serviceRPC: Close: %v", err) } }() expectedContentType := fmt.Sprintf("application/x-git-%s-request", service) - if h.r.Header.Get("Content-Type") != expectedContentType { - log.Error("Content-Type (%q) doesn't match expected: %q", h.r.Header.Get("Content-Type"), expectedContentType) - h.w.WriteHeader(http.StatusUnauthorized) + if ctx.Req.Header.Get("Content-Type") != expectedContentType { + log.Error("Content-Type (%q) doesn't match expected: %q", ctx.Req.Header.Get("Content-Type"), expectedContentType) + ctx.Resp.WriteHeader(http.StatusUnauthorized) return } - cmd, err := prepareGitCmdWithAllowedService(service, h) + cmd, err := prepareGitCmdWithAllowedService(ctx, service) if err != nil { log.Error("Failed to prepareGitCmdWithService: %v", err) - h.w.WriteHeader(http.StatusUnauthorized) + ctx.Resp.WriteHeader(http.StatusUnauthorized) return } - h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service)) + ctx.Resp.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service)) - reqBody := h.r.Body + reqBody := ctx.Req.Body // Handle GZIP. - if h.r.Header.Get("Content-Encoding") == "gzip" { + if ctx.Req.Header.Get("Content-Encoding") == "gzip" { reqBody, err = gzip.NewReader(reqBody) if err != nil { log.Error("Fail to create gzip reader: %v", err) - h.w.WriteHeader(http.StatusInternalServerError) + ctx.Resp.WriteHeader(http.StatusInternalServerError) return } } @@ -466,23 +451,23 @@ func serviceRPC(h *serviceHandler, service string) { // set this for allow pre-receive and post-receive execute h.environ = append(h.environ, "SSH_ORIGINAL_COMMAND="+service) - if protocol := h.r.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) { + if protocol := ctx.Req.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) { h.environ = append(h.environ, "GIT_PROTOCOL="+protocol) } var stderr bytes.Buffer - cmd.AddArguments("--stateless-rpc").AddDynamicArguments(h.dir) - cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir)) + cmd.AddArguments("--stateless-rpc").AddDynamicArguments(h.getRepoDir()) + cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.getRepoDir())) if err := cmd.Run(&git.RunOpts{ - Dir: h.dir, + Dir: h.getRepoDir(), Env: append(os.Environ(), h.environ...), - Stdout: h.w, + Stdout: ctx.Resp, Stdin: reqBody, Stderr: &stderr, UseContextTimeout: true, }); err != nil { if err.Error() != "signal: killed" { - log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String()) + log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.getRepoDir(), err, stderr.String()) } return } @@ -492,7 +477,7 @@ func serviceRPC(h *serviceHandler, service string) { func ServiceUploadPack(ctx *context.Context) { h := httpBase(ctx) if h != nil { - serviceRPC(h, "upload-pack") + serviceRPC(ctx, h, "upload-pack") } } @@ -500,12 +485,12 @@ func ServiceUploadPack(ctx *context.Context) { func ServiceReceivePack(ctx *context.Context) { h := httpBase(ctx) if h != nil { - serviceRPC(h, "receive-pack") + serviceRPC(ctx, h, "receive-pack") } } -func getServiceType(r *http.Request) string { - serviceType := r.FormValue("service") +func getServiceType(ctx *context.Context) string { + serviceType := ctx.Req.FormValue("service") if !strings.HasPrefix(serviceType, "git-") { return "" } @@ -534,28 +519,28 @@ func GetInfoRefs(ctx *context.Context) { if h == nil { return } - h.setHeaderNoCache() - service := getServiceType(h.r) - cmd, err := prepareGitCmdWithAllowedService(service, h) + setHeaderNoCache(ctx) + service := getServiceType(ctx) + cmd, err := prepareGitCmdWithAllowedService(ctx, service) if err == nil { - if protocol := h.r.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) { + if protocol := ctx.Req.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) { h.environ = append(h.environ, "GIT_PROTOCOL="+protocol) } h.environ = append(os.Environ(), h.environ...) - refs, _, err := cmd.AddArguments("--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Env: h.environ, Dir: h.dir}) + refs, _, err := cmd.AddArguments("--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Env: h.environ, Dir: h.getRepoDir()}) if err != nil { log.Error(fmt.Sprintf("%v - %s", err, string(refs))) } - h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service)) - h.w.WriteHeader(http.StatusOK) - _, _ = h.w.Write(packetWrite("# service=git-" + service + "\n")) - _, _ = h.w.Write([]byte("0000")) - _, _ = h.w.Write(refs) + ctx.Resp.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service)) + ctx.Resp.WriteHeader(http.StatusOK) + _, _ = ctx.Resp.Write(packetWrite("# service=git-" + service + "\n")) + _, _ = ctx.Resp.Write([]byte("0000")) + _, _ = ctx.Resp.Write(refs) } else { - updateServerInfo(ctx, h.dir) - h.sendFile("text/plain; charset=utf-8", "info/refs") + updateServerInfo(ctx, h.getRepoDir()) + h.sendFile(ctx, "text/plain; charset=utf-8", "info/refs") } } @@ -564,12 +549,12 @@ func GetTextFile(p string) func(*context.Context) { return func(ctx *context.Context) { h := httpBase(ctx) if h != nil { - h.setHeaderNoCache() + setHeaderNoCache(ctx) file := ctx.Params("file") if file != "" { - h.sendFile("text/plain", "objects/info/"+file) + h.sendFile(ctx, "text/plain", "objects/info/"+file) } else { - h.sendFile("text/plain", p) + h.sendFile(ctx, "text/plain", p) } } } @@ -579,8 +564,8 @@ func GetTextFile(p string) func(*context.Context) { func GetInfoPacks(ctx *context.Context) { h := httpBase(ctx) if h != nil { - h.setHeaderCacheForever() - h.sendFile("text/plain; charset=utf-8", "objects/info/packs") + setHeaderCacheForever(ctx) + h.sendFile(ctx, "text/plain; charset=utf-8", "objects/info/packs") } } @@ -588,8 +573,8 @@ func GetInfoPacks(ctx *context.Context) { func GetLooseObject(ctx *context.Context) { h := httpBase(ctx) if h != nil { - h.setHeaderCacheForever() - h.sendFile("application/x-git-loose-object", fmt.Sprintf("objects/%s/%s", + setHeaderCacheForever(ctx) + h.sendFile(ctx, "application/x-git-loose-object", fmt.Sprintf("objects/%s/%s", ctx.Params("head"), ctx.Params("hash"))) } } @@ -598,8 +583,8 @@ func GetLooseObject(ctx *context.Context) { func GetPackFile(ctx *context.Context) { h := httpBase(ctx) if h != nil { - h.setHeaderCacheForever() - h.sendFile("application/x-git-packed-objects", "objects/pack/pack-"+ctx.Params("file")+".pack") + setHeaderCacheForever(ctx) + h.sendFile(ctx, "application/x-git-packed-objects", "objects/pack/pack-"+ctx.Params("file")+".pack") } } @@ -607,7 +592,7 @@ func GetPackFile(ctx *context.Context) { func GetIdxFile(ctx *context.Context) { h := httpBase(ctx) if h != nil { - h.setHeaderCacheForever() - h.sendFile("application/x-git-packed-objects-toc", "objects/pack/pack-"+ctx.Params("file")+".idx") + setHeaderCacheForever(ctx) + h.sendFile(ctx, "application/x-git-packed-objects-toc", "objects/pack/pack-"+ctx.Params("file")+".idx") } } From 4989ad0a9f097fdd8d642aa10f4c203f861debea Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Thu, 1 Feb 2024 00:36:23 +0200 Subject: [PATCH 04/11] Add htmx guidelines (#28993) To make sure we don't abuse it. --------- Signed-off-by: Yarden Shoham Co-authored-by: wxiaoguang Co-authored-by: delvh --- docs/content/contributing/guidelines-frontend.en-us.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/content/contributing/guidelines-frontend.en-us.md b/docs/content/contributing/guidelines-frontend.en-us.md index aa1759d9c9..edd89e1231 100644 --- a/docs/content/contributing/guidelines-frontend.en-us.md +++ b/docs/content/contributing/guidelines-frontend.en-us.md @@ -65,14 +65,17 @@ Recommended implementations: * Vue + Vanilla JS * Fomantic-UI (jQuery) +* htmx (partial page reloads for otherwise static components) * Vanilla JS Discouraged implementations: * Vue + Fomantic-UI (jQuery) * jQuery + Vanilla JS +* htmx + any other framework which requires heavy JS code, or unnecessary features like htmx scripting (`hx-on`) To make UI consistent, Vue components can use Fomantic-UI CSS classes. +We use htmx for simple interactions. You can see an example for simple interactions where htmx should be used in this [PR](https://github.com/go-gitea/gitea/pull/28908). Do not use htmx if you require more advanced reactivity, use another framework (Vue/Vanilla JS). Although mixing different frameworks is discouraged, it should also work if the mixing is necessary and the code is well-designed and maintainable. From 64faecefe10613840709a68c1b8b708115d69d6e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 1 Feb 2024 09:04:23 +0900 Subject: [PATCH 05/11] Fix UI Spacing Errors in mirror settings (#28990) --- options/locale/locale_en-US.ini | 1 + templates/repo/settings/options.tmpl | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index c1e2967d03..9af4d70171 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2013,6 +2013,7 @@ settings.mirror_settings.docs.doc_link_title = How do I mirror repositories? settings.mirror_settings.docs.doc_link_pull_section = the "Pulling from a remote repository" section of the documentation. settings.mirror_settings.docs.pulling_remote_title = Pulling from a remote repository settings.mirror_settings.mirrored_repository = Mirrored repository +settings.mirror_settings.pushed_repository = Pushed repository settings.mirror_settings.direction = Direction settings.mirror_settings.direction.pull = Pull settings.mirror_settings.direction.push = Push diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 07b2f58d53..dfb909e743 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -105,8 +105,9 @@ {{else}} {{ctx.Locale.Tr "repo.settings.mirror_settings.docs.no_new_mirrors"}} {{ctx.Locale.Tr "repo.settings.mirror_settings.docs.can_still_use"}}
{{end}} + + {{if .Repository.IsMirror}} - {{if $existingPushMirror}} @@ -200,8 +201,18 @@ - - {{end}}{{/* end if: IsMirror */}} +
{{ctx.Locale.Tr "repo.settings.mirror_settings.mirrored_repository"}}
+ {{end}}{{/* end if: IsMirror */}} + + + + + + + + + + {{range .PushMirrors}} From ab45f9ee12a9f4fee6a5228bce586130568cc7b9 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 1 Feb 2024 00:25:05 +0000 Subject: [PATCH 06/11] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 77414f1570..faa1215d5b 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -17,6 +17,7 @@ template=模板 language=语言选项 notifications=通知 active_stopwatch=活动时间跟踪器 +tracked_time_summary=基于问题列表过滤器的跟踪时间概要 create_new=创建… user_profile_and_more=个人信息和配置 signed_in_as=已登录用户 @@ -90,6 +91,7 @@ remove=移除 remove_all=移除所有 remove_label_str=`删除标签 "%s"` edit=编辑 +view=查看 enabled=启用 disabled=禁用 @@ -359,6 +361,7 @@ disable_register_prompt=对不起,注册功能已被关闭。请联系网站 disable_register_mail=已禁用注册的电子邮件确认。 manual_activation_only=请联系您的站点管理员来完成激活。 remember_me=记住此设备 +remember_me.compromised=登录令牌不再有效,因为它可能表明帐户已被破坏。请检查您的帐户是否有异常活动。 forgot_password_title=忘记密码 forgot_password=忘记密码? sign_up_now=还没帐户?马上注册。 @@ -862,6 +865,7 @@ revoke_oauth2_grant_description=确定撤销此三方应用程序的授权,并 revoke_oauth2_grant_success=成功撤销了访问权限。 twofa_desc=两步验证可以加强你的账号安全性。 +twofa_recovery_tip=如果您丢失了您的设备,您将能够使用一次性恢复密钥来重新获得对您账户的访问。 twofa_is_enrolled=你的账号已启用了两步验证。 twofa_not_enrolled=你的账号未开启两步验证。 twofa_disable=禁用两步认证 @@ -884,6 +888,8 @@ webauthn_register_key=添加安全密钥 webauthn_nickname=昵称 webauthn_delete_key=移除安全密钥 webauthn_delete_key_desc=如果删除了安全密钥,则不能再使用它登录。继续? +webauthn_key_loss_warning=如果您丢失了您的安全密钥,您将无法访问您的帐户。 +webauthn_alternative_tip=您可能想要配置额外的身份验证方法。 manage_account_links=管理绑定过的账号 manage_account_links_desc=这些外部帐户已经绑定到您的 Gitea 帐户。 @@ -920,6 +926,7 @@ visibility.private=私有 visibility.private_tooltip=仅对您已加入的组织的成员可见。 [repo] +new_repo_helper=代码仓库包含了所有的项目文件,包括版本历史记录。已经在其他地方托管了?迁移仓库。 owner=拥有者 owner_helper=由于最大仓库数量限制,一些组织可能不会显示在下拉列表中。 repo_name=仓库名称 @@ -1782,6 +1789,8 @@ pulls.status_checks_failure=一些检查失败了 pulls.status_checks_error=一些检查报告了错误 pulls.status_checks_requested=必须 pulls.status_checks_details=详情 +pulls.status_checks_hide_all=隐藏所有检查 +pulls.status_checks_show_all=显示所有检查 pulls.update_branch=通过合并更新分支 pulls.update_branch_rebase=通过变基更新分支 pulls.update_branch_success=分支更新成功 @@ -1790,6 +1799,11 @@ pulls.outdated_with_base_branch=此分支相比基础分支已过期 pulls.close=关闭合并请求 pulls.closed_at=`于 %[2]s 关闭此合并请求 ` pulls.reopened_at=`重新打开此合并请求 %[2]s` +pulls.cmd_instruction_hint=`查看 命令行提示。` +pulls.cmd_instruction_checkout_title=检出 +pulls.cmd_instruction_checkout_desc=从你的仓库中检出一个新的分支并测试变更。 +pulls.cmd_instruction_merge_title=合并 +pulls.cmd_instruction_merge_desc=合并变更并更新到 Gitea 上 pulls.clear_merge_message=清除合并信息 pulls.clear_merge_message_hint=清除合并消息只会删除提交消息内容,并保留生成的 git 附加内容,如“Co-Authored-By …”。 @@ -2301,6 +2315,7 @@ settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被 settings.require_signed_commits=需要签名提交 settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支 settings.protect_branch_name_pattern=受保护的分支名称模式 +settings.protect_branch_name_pattern_desc=分支保护的名称匹配规则。语法请参阅 文档 。如:main, release/** settings.protect_patterns=规则 settings.protect_protected_file_patterns=受保护的文件模式(使用分号 ';' 分隔): settings.protect_protected_file_patterns_desc=即使用户有权添加、编辑或删除此分支中的文件,也不允许直接更改受保护的文件。 可以使用分号 (';') 分隔多个模式。 见github.com/gobwas/glob文档了解模式语法。例如: .drone.yml, /docs/**/*.txt @@ -2365,7 +2380,7 @@ settings.lfs_findcommits=查找提交 settings.lfs_lfs_file_no_commits=没有找到关于此 LFS 文件的提交 settings.lfs_noattribute=此路径在默认分支中没有可锁定的属性 settings.lfs_delete=删除 OID 为 %s 的 LFS 文件 -settings.lfs_delete_warning=删除一个 LFS 文件可能导致签出时显示'对象不存在'的错误。确定继续吗? +settings.lfs_delete_warning=删除一个 LFS 文件可能导致检出时显示'对象不存在'的错误。确定继续吗? settings.lfs_findpointerfiles=查找指针文件 settings.lfs_locks=锁定 settings.lfs_invalid_locking_path=无效路径:%s @@ -2846,6 +2861,7 @@ emails.updated=电子邮件已更新 emails.not_updated=无法更新请求的电子邮件地址: %v emails.duplicate_active=此电子邮件地址已被另一个用户激活使用。 emails.change_email_header=更新电子邮件属性 +emails.change_email_text=您确定要更新该电子邮件地址吗? orgs.org_manage_panel=组织管理 orgs.name=名称 @@ -2870,6 +2886,7 @@ packages.package_manage_panel=软件包管理 packages.total_size=总大小:%s packages.unreferenced_size=未引用大小: %s packages.cleanup=清理过期数据 +packages.cleanup.success=清理过期数据成功 packages.owner=所有者 packages.creator=创建者 packages.name=名称 @@ -3508,12 +3525,17 @@ runs.commit=提交 runs.scheduled=已计划的 runs.pushed_by=推送者 runs.invalid_workflow_helper=工作流配置文件无效。请检查您的配置文件: %s +runs.no_matching_online_runner_helper=没有匹配标签的在线 runner: %s runs.actor=操作者 runs.status=状态 runs.actors_no_select=所有操作者 runs.status_no_select=所有状态 runs.no_results=没有匹配的结果。 +runs.no_workflows=目前还没有工作流。 +runs.no_workflows.quick_start=不知道如何启动Gitea Action?请参阅 快速启动指南 +runs.no_workflows.documentation=更多有关 Gitea Action 的信息,请访问 文档。 runs.no_runs=工作流尚未运行过。 +runs.empty_commit_message=(空白的提交消息) workflow.disable=禁用工作流 workflow.disable_success=工作流 '%s' 已成功禁用。 From a1e0d8bd8bf3ad747673496c4059ec8ed42c9128 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 1 Feb 2024 02:43:06 +0100 Subject: [PATCH 07/11] Update dorny/paths-filter action (#29003) --- .github/workflows/files-changed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index e7039053af..c909f78597 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -35,7 +35,7 @@ jobs: yaml: ${{ steps.changes.outputs.yaml }} steps: - uses: actions/checkout@v4 - - uses: dorny/paths-filter@v2 + - uses: dorny/paths-filter@v3 id: changes with: filters: | From 3a667621306216b1724ba1a9b23d61a4f7aff50d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 1 Feb 2024 14:25:37 +0800 Subject: [PATCH 08/11] Revert "Speed up loading the dashboard on mysql/mariadb (#28546)" (#29006) This reverts commit fa8c3beb26acfcc7e732038c947225857ebcbf31. #28546 Because it seems performance become worse. --- models/activities/action.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/models/activities/action.go b/models/activities/action.go index c9745e4a8a..15bd9a52ac 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -446,12 +446,9 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err return nil, 0, err } - sess := db.GetEngine(ctx).Where(cond) - if setting.Database.Type.IsMySQL() { - sess = sess.IndexHint("USE", "JOIN", "IDX_action_c_u_d") - } - sess = sess.Select("`action`.*"). // this line will avoid select other joined table's columns - Join("INNER", "repository", "`repository`.id = `action`.repo_id") + sess := db.GetEngine(ctx).Where(cond). + Select("`action`.*"). // this line will avoid select other joined table's columns + Join("INNER", "repository", "`repository`.id = `action`.repo_id") opts.SetDefaultValues() sess = db.SetSessionPagination(sess, &opts) From c3e462921ee31536e59b37e654ed20e92a37ffe6 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 1 Feb 2024 18:10:16 +0100 Subject: [PATCH 09/11] Improve user search display name (#29002) I tripped over this strange method and I don't think we need that workaround to fix the value. old: ![grafik](https://github.com/go-gitea/gitea/assets/1666336/c8b6797b-eb45-4dec-99db-1b0649a34ec5) new: ![grafik](https://github.com/go-gitea/gitea/assets/1666336/ab1a65ae-de5b-4ce4-9813-3b8b39c7922e) --------- Co-authored-by: silverwind Co-authored-by: wxiaoguang --- routers/utils/utils.go | 8 -------- routers/utils/utils_test.go | 6 ------ routers/web/org/teams.go | 3 +-- routers/web/repo/setting/collaboration.go | 5 ++--- web_src/css/base.css | 4 ++++ web_src/css/repo.css | 8 +++++--- web_src/js/features/comp/SearchUserBox.js | 9 ++++----- web_src/js/features/repo-settings.js | 4 ++-- 8 files changed, 18 insertions(+), 29 deletions(-) diff --git a/routers/utils/utils.go b/routers/utils/utils.go index d6856fceac..1f4d11fd3c 100644 --- a/routers/utils/utils.go +++ b/routers/utils/utils.go @@ -11,14 +11,6 @@ import ( "code.gitea.io/gitea/modules/setting" ) -// RemoveUsernameParameterSuffix returns the username parameter without the (fullname) suffix - leaving just the username -func RemoveUsernameParameterSuffix(name string) string { - if index := strings.Index(name, " ("); index >= 0 { - name = name[:index] - } - return name -} - // SanitizeFlashErrorString will sanitize a flash error string func SanitizeFlashErrorString(x string) string { return strings.ReplaceAll(html.EscapeString(x), "\n", "
") diff --git a/routers/utils/utils_test.go b/routers/utils/utils_test.go index 6d19214c88..440aad87c6 100644 --- a/routers/utils/utils_test.go +++ b/routers/utils/utils_test.go @@ -11,12 +11,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRemoveUsernameParameterSuffix(t *testing.T) { - assert.Equal(t, "foobar", RemoveUsernameParameterSuffix("foobar (Foo Bar)")) - assert.Equal(t, "foobar", RemoveUsernameParameterSuffix("foobar")) - assert.Equal(t, "", RemoveUsernameParameterSuffix("")) -} - func TestIsExternalURL(t *testing.T) { setting.AppURL = "https://try.gitea.io/" type test struct { diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 9e65c8ba9c..71fe99c97c 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -24,7 +24,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/routers/utils" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" @@ -127,7 +126,7 @@ func TeamsAction(ctx *context.Context) { ctx.Error(http.StatusNotFound) return } - uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("uname"))) + uname := strings.ToLower(ctx.FormString("uname")) var u *user_model.User u, err = user_model.GetUserByName(ctx, uname) if err != nil { diff --git a/routers/web/repo/setting/collaboration.go b/routers/web/repo/setting/collaboration.go index e217697cc0..c5c2a88c49 100644 --- a/routers/web/repo/setting/collaboration.go +++ b/routers/web/repo/setting/collaboration.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/routers/utils" "code.gitea.io/gitea/services/mailer" org_service "code.gitea.io/gitea/services/org" repo_service "code.gitea.io/gitea/services/repository" @@ -52,7 +51,7 @@ func Collaboration(ctx *context.Context) { // CollaborationPost response for actions for a collaboration of a repository func CollaborationPost(ctx *context.Context) { - name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("collaborator"))) + name := strings.ToLower(ctx.FormString("collaborator")) if len(name) == 0 || ctx.Repo.Owner.LowerName == name { ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath()) return @@ -144,7 +143,7 @@ func AddTeamPost(ctx *context.Context) { return } - name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("team"))) + name := strings.ToLower(ctx.FormString("team")) if len(name) == 0 { ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") return diff --git a/web_src/css/base.css b/web_src/css/base.css index cc1f6a8397..198e87c0e2 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -196,10 +196,14 @@ a.label, .ui.search > .results { background: var(--color-body); border-color: var(--color-secondary); + overflow-wrap: anywhere; /* allow text to wrap as fomantic limits this to 18em width */ } .ui.search > .results .result { background: var(--color-body); + border-color: var(--color-secondary); + display: flex; + align-items: center; } .ui.search > .results .result .title { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index dfe0d6c77f..55c6ec4817 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2128,14 +2128,16 @@ } #search-user-box .results .result .image { - float: left; - margin-right: 8px; + order: 0; + margin-right: 12px; width: 2em; height: 2em; + min-width: 2em; + min-height: 2em; } #search-user-box .results .result .content { - margin: 6px 0; /* this trick is used to align with the sibling avatar image */ + margin: 0; /* remove margin reserved for avatar because we move it to left via `order: 0` */ } .ui.menu .item > img:not(.ui) { diff --git a/web_src/js/features/comp/SearchUserBox.js b/web_src/js/features/comp/SearchUserBox.js index 960b787fea..992d4ef020 100644 --- a/web_src/js/features/comp/SearchUserBox.js +++ b/web_src/js/features/comp/SearchUserBox.js @@ -17,14 +17,13 @@ export function initCompSearchUserBox() { const searchQuery = $searchUserBox.find('input').val(); const searchQueryUppercase = searchQuery.toUpperCase(); $.each(response.data, (_i, item) => { - let title = item.login; - if (item.full_name && item.full_name.length > 0) { - title += ` (${htmlEscape(item.full_name)})`; - } const resultItem = { - title, + title: item.login, image: item.avatar_url }; + if (item.full_name) { + resultItem.description = htmlEscape(item.full_name); + } if (searchQueryUppercase === item.login.toUpperCase()) { items.unshift(resultItem); } else { diff --git a/web_src/js/features/repo-settings.js b/web_src/js/features/repo-settings.js index 04974200bb..75e624a6a7 100644 --- a/web_src/js/features/repo-settings.js +++ b/web_src/js/features/repo-settings.js @@ -52,9 +52,9 @@ export function initRepoSettingSearchTeamBox() { onResponse(response) { const items = []; $.each(response.data, (_i, item) => { - const title = `${item.name} (${item.permission} access)`; items.push({ - title, + title: item.name, + description: `${item.permission} access` // TODO: translate this string }); }); From b71850ea731ffd04f87f32fe25373a9c103ed669 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 1 Feb 2024 22:01:48 +0100 Subject: [PATCH 10/11] Strip trailing newline in markdown code copy (#29019) Behaviour now matches GH. Safeguard added in the for loop because `textContent` may be null in which case it does not make sense to render the copy button. --- web_src/js/markup/codecopy.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web_src/js/markup/codecopy.js b/web_src/js/markup/codecopy.js index a12802ef73..078d741253 100644 --- a/web_src/js/markup/codecopy.js +++ b/web_src/js/markup/codecopy.js @@ -12,8 +12,10 @@ export function renderCodeCopy() { if (!els.length) return; for (const el of els) { + if (!el.textContent) continue; const btn = makeCodeCopyButton(); - btn.setAttribute('data-clipboard-text', el.textContent); + // remove final trailing newline introduced during HTML rendering + btn.setAttribute('data-clipboard-text', el.textContent.replace(/\r?\n$/, '')); el.after(btn); } } From e6265cf59dc579ba4564fbafd0ef24f9aa6e26a8 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 2 Feb 2024 05:28:50 +0800 Subject: [PATCH 11/11] Fix incorrect button CSS usages (#29015) --- templates/repo/settings/lfs_file.tmpl | 2 +- templates/repo/unicode_escape_prompt.tmpl | 4 ++-- templates/repo/view_file.tmpl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index bb2e25e86c..0aeb2af178 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -33,7 +33,7 @@ {{else if .IsPDFFile}}
{{else}} - {{ctx.Locale.Tr "repo.file_view_raw"}} + {{ctx.Locale.Tr "repo.file_view_raw"}} {{end}} {{else if .FileSize}} diff --git a/templates/repo/unicode_escape_prompt.tmpl b/templates/repo/unicode_escape_prompt.tmpl index 8f02a489e9..d0730f23c1 100644 --- a/templates/repo/unicode_escape_prompt.tmpl +++ b/templates/repo/unicode_escape_prompt.tmpl @@ -1,7 +1,7 @@ {{if .EscapeStatus}} {{if .EscapeStatus.HasInvisible}}
- +
{{ctx.Locale.Tr "repo.invisible_runes_header"}}
@@ -12,7 +12,7 @@
{{else if .EscapeStatus.HasAmbiguous}}
- +
{{ctx.Locale.Tr "repo.ambiguous_runes_header"}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index e6591df7e3..1f9e0b5028 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -108,7 +108,7 @@ {{else if .IsPDFFile}}
{{else}} - {{ctx.Locale.Tr "repo.file_view_raw"}} + {{ctx.Locale.Tr "repo.file_view_raw"}} {{end}}
{{else if .FileSize}}
{{ctx.Locale.Tr "repo.settings.mirror_settings.pushed_repository"}}{{ctx.Locale.Tr "repo.settings.mirror_settings.direction"}}{{ctx.Locale.Tr "repo.settings.mirror_settings.last_update"}}