summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules/context/context_response.go1
-rw-r--r--modules/git/commit.go26
-rw-r--r--modules/git/repo_ref.go54
-rw-r--r--options/locale/locale_en-US.ini3
-rw-r--r--routers/web/repo/commit.go15
-rw-r--r--routers/web/web.go1
-rw-r--r--services/repository/commit.go55
-rw-r--r--templates/repo/commit_load_branches_and_tags.tmpl18
-rw-r--r--templates/repo/commit_page.tmpl7
-rw-r--r--templates/repo/commits_list.tmpl2
-rw-r--r--templates/repo/commits_list_small.tmpl2
-rw-r--r--templates/repo/view_list.tmpl2
-rw-r--r--web_src/js/features/repo-commit.js2
-rw-r--r--web_src/js/features/repo-diff-commit.js52
-rw-r--r--web_src/js/features/repo-legacy.js2
-rw-r--r--web_src/js/index.js2
16 files changed, 202 insertions, 42 deletions
diff --git a/modules/context/context_response.go b/modules/context/context_response.go
index bb3ccf69ce..9dc6d1fc0e 100644
--- a/modules/context/context_response.go
+++ b/modules/context/context_response.go
@@ -166,6 +166,7 @@ func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
// NotFoundOrServerError use error check function to determine if the error
// is about not found. It responds with 404 status code for not found error,
// or error context description for logging purpose of 500 server error.
+// TODO: remove the "errCheck" and use util.ErrNotFound to check
func (ctx *Context) NotFoundOrServerError(logMsg string, errCheck func(error) bool, logErr error) {
if errCheck(logErr) {
ctx.notFoundInternal(logMsg, logErr)
diff --git a/modules/git/commit.go b/modules/git/commit.go
index 729e3b4672..c44882d886 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -20,7 +20,6 @@ import (
// Commit represents a git commit.
type Commit struct {
- Branch string // Branch this commit belongs to
Tree
ID SHA1 // The ID of this commit object
Author *Signature
@@ -432,31 +431,6 @@ func (c *Commit) GetBranchName() (string, error) {
return strings.SplitN(strings.TrimSpace(data), "~", 2)[0], nil
}
-// LoadBranchName load branch name for commit
-func (c *Commit) LoadBranchName() (err error) {
- if len(c.Branch) != 0 {
- return nil
- }
-
- c.Branch, err = c.GetBranchName()
- return err
-}
-
-// GetTagName gets the current tag name for given commit
-func (c *Commit) GetTagName() (string, error) {
- data, _, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always").AddDynamicArguments(c.ID.String()).RunStdString(&RunOpts{Dir: c.repo.Path})
- if err != nil {
- // handle special case where there is no tag for this commit
- if strings.Contains(err.Error(), "no tag exactly matches") {
- return "", nil
- }
-
- return "", err
- }
-
- return strings.TrimSpace(data), nil
-}
-
// CommitFileStatus represents status of files in a commit.
type CommitFileStatus struct {
Added []string
diff --git a/modules/git/repo_ref.go b/modules/git/repo_ref.go
index 54e424bb83..8eaa17cb04 100644
--- a/modules/git/repo_ref.go
+++ b/modules/git/repo_ref.go
@@ -3,7 +3,61 @@
package git
+import (
+ "context"
+ "strings"
+
+ "code.gitea.io/gitea/modules/util"
+)
+
// GetRefs returns all references of the repository.
func (repo *Repository) GetRefs() ([]*Reference, error) {
return repo.GetRefsFiltered("")
}
+
+// ListOccurrences lists all refs of the given refType the given commit appears in sorted by creation date DESC
+// refType should only be a literal "branch" or "tag" and nothing else
+func (repo *Repository) ListOccurrences(ctx context.Context, refType, commitSHA string) ([]string, error) {
+ cmd := NewCommand(ctx)
+ if refType == "branch" {
+ cmd.AddArguments("branch")
+ } else if refType == "tag" {
+ cmd.AddArguments("tag")
+ } else {
+ return nil, util.NewInvalidArgumentErrorf(`can only use "branch" or "tag" for refType, but got %q`, refType)
+ }
+ stdout, _, err := cmd.AddArguments("--no-color", "--sort=-creatordate", "--contains").AddDynamicArguments(commitSHA).RunStdString(&RunOpts{Dir: repo.Path})
+ if err != nil {
+ return nil, err
+ }
+
+ refs := strings.Split(strings.TrimSpace(stdout), "\n")
+ if refType == "branch" {
+ return parseBranches(refs), nil
+ }
+ return parseTags(refs), nil
+}
+
+func parseBranches(refs []string) []string {
+ results := make([]string, 0, len(refs))
+ for _, ref := range refs {
+ if strings.HasPrefix(ref, "* ") { // current branch (main branch)
+ results = append(results, ref[len("* "):])
+ } else if strings.HasPrefix(ref, " ") { // all other branches
+ results = append(results, ref[len(" "):])
+ } else if ref != "" {
+ results = append(results, ref)
+ }
+ }
+ return results
+}
+
+func parseTags(refs []string) []string {
+ results := make([]string, 0, len(refs))
+ for _, ref := range refs {
+ if ref != "" {
+ results = append(results, ref)
+ }
+ }
+ return results
+}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 25fb155435..dc88c422b5 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1170,6 +1170,9 @@ commit_graph.select = Select branches
commit_graph.hide_pr_refs = Hide Pull Requests
commit_graph.monochrome = Mono
commit_graph.color = Color
+commit.contained_in = This commit is contained in:
+commit.contained_in_default_branch = This commit is part of the default branch
+commit.load_referencing_branches_and_tags = Load branches and tags referencing this commit
blame = Blame
download_file = Download file
normal_view = Normal View
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index e88f1139f8..5b32591b89 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/gitdiff"
+ git_service "code.gitea.io/gitea/services/repository"
)
const (
@@ -255,6 +256,15 @@ func FileHistory(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplCommits)
}
+func LoadBranchesAndTags(ctx *context.Context) {
+ response, err := git_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.Params("sha"))
+ if err == nil {
+ ctx.JSON(http.StatusOK, response)
+ return
+ }
+ ctx.NotFoundOrServerError(fmt.Sprintf("could not load branches and tags the commit %s belongs to", ctx.Params("sha")), git.IsErrNotExist, err)
+}
+
// Diff show different from current commit to previous commit
func Diff(ctx *context.Context) {
ctx.Data["PageIsDiff"] = true
@@ -374,11 +384,6 @@ func Diff(ctx *context.Context) {
return
}
- ctx.Data["TagName"], err = commit.GetTagName()
- if err != nil {
- ctx.ServerError("commit.GetTagName", err)
- return
- }
ctx.HTML(http.StatusOK, tplCommitPage)
}
diff --git a/routers/web/web.go b/routers/web/web.go
index d7ef2fb82f..0b51961445 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1337,6 +1337,7 @@ func registerRoutes(m *web.Route) {
m.Group("", func() {
m.Get("/graph", repo.Graph)
m.Get("/commit/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
+ m.Get("/commit/{sha:([a-f0-9]{7,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
diff --git a/services/repository/commit.go b/services/repository/commit.go
new file mode 100644
index 0000000000..2497910a83
--- /dev/null
+++ b/services/repository/commit.go
@@ -0,0 +1,55 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+ "context"
+ "fmt"
+
+ gitea_ctx "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/util"
+)
+
+type ContainedLinks struct { // TODO: better name?
+ Branches []*namedLink `json:"branches"`
+ Tags []*namedLink `json:"tags"`
+ DefaultBranch string `json:"default_branch"`
+}
+
+type namedLink struct { // TODO: better name?
+ Name string `json:"name"`
+ WebLink string `json:"web_link"`
+}
+
+// LoadBranchesAndTags creates a new repository branch
+func LoadBranchesAndTags(ctx context.Context, baseRepo *gitea_ctx.Repository, commitSHA string) (*ContainedLinks, error) {
+ containedTags, err := baseRepo.GitRepo.ListOccurrences(ctx, "tag", commitSHA)
+ if err != nil {
+ return nil, fmt.Errorf("encountered a problem while querying %s: %w", "tags", err)
+ }
+ containedBranches, err := baseRepo.GitRepo.ListOccurrences(ctx, "branch", commitSHA)
+ if err != nil {
+ return nil, fmt.Errorf("encountered a problem while querying %s: %w", "branches", err)
+ }
+
+ result := &ContainedLinks{
+ DefaultBranch: baseRepo.Repository.DefaultBranch,
+ Branches: make([]*namedLink, 0, len(containedBranches)),
+ Tags: make([]*namedLink, 0, len(containedTags)),
+ }
+ for _, tag := range containedTags {
+ // TODO: Use a common method to get the link to a branch/tag instead of hard-coding it here
+ result.Tags = append(result.Tags, &namedLink{
+ Name: tag,
+ WebLink: fmt.Sprintf("%s/src/tag/%s", baseRepo.RepoLink, util.PathEscapeSegments(tag)),
+ })
+ }
+ for _, branch := range containedBranches {
+ result.Branches = append(result.Branches, &namedLink{
+ Name: branch,
+ WebLink: fmt.Sprintf("%s/src/branch/%s", baseRepo.RepoLink, util.PathEscapeSegments(branch)),
+ })
+ }
+ return result, nil
+}
diff --git a/templates/repo/commit_load_branches_and_tags.tmpl b/templates/repo/commit_load_branches_and_tags.tmpl
new file mode 100644
index 0000000000..c19aa55c56
--- /dev/null
+++ b/templates/repo/commit_load_branches_and_tags.tmpl
@@ -0,0 +1,18 @@
+<div class="branch-and-tag-area" data-text-default-branch-tooltip="{{.locale.Tr "repo.commit.contained_in_default_branch"}}">
+ <button class="ui button ellipsis-button load-branches-and-tags gt-mt-3" aria-expanded="false"
+ data-fetch-url="{{.RepoLink}}/commit/{{.CommitID}}/load-branches-and-tags"
+ data-tooltip-content="{{.locale.Tr "repo.commit.load_referencing_branches_and_tags"}}"
+ >...</button>
+ <div class="branch-and-tag-detail gt-hidden">
+ <div class="divider"></div>
+ <div>{{.locale.Tr "repo.commit.contained_in"}}</div>
+ <div class="gt-df gt-mt-3">
+ <div class="gt-p-2">{{svg "octicon-git-branch"}}</div>
+ <div class="branch-area flex-text-block gt-f1"></div>
+ </div>
+ <div class="gt-df gt-mt-3">
+ <div class="gt-p-2">{{svg "octicon-tag"}}</div>
+ <div class="tag-area flex-text-block gt-f1"></div>
+ </div>
+ </div>
+</div>
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl
index e4aad30fa7..bd33a30443 100644
--- a/templates/repo/commit_page.tmpl
+++ b/templates/repo/commit_page.tmpl
@@ -137,12 +137,7 @@
{{if IsMultilineCommitMessage .Commit.Message}}
<pre class="commit-body gt-mt-0">{{RenderCommitBody $.Context .Commit.Message $.RepoLink $.Repository.ComposeMetas}}</pre>
{{end}}
- {{if .BranchName}}
- <span class="text grey gt-mr-3">{{svg "octicon-git-branch" 16 "gt-mr-2"}}{{.BranchName}}</span>
- {{end}}
- {{if .TagName}}
- <span class="text grey gt-mr-3">{{svg "octicon-tag" 16 "gt-mr-2"}}{{.TagName}}</span>
- {{end}}
+ {{template "repo/commit_load_branches_and_tags" .}}
</div>
<div class="ui attached segment gt-df gt-ac gt-sb gt-py-2 commit-header-row gt-fw {{$class}}">
<div class="gt-df gt-ac author">
diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl
index 6768bcb513..ef9d065456 100644
--- a/templates/repo/commits_list.tmpl
+++ b/templates/repo/commits_list.tmpl
@@ -70,7 +70,7 @@
{{end}}
</span>
{{if IsMultilineCommitMessage .Message}}
- <button class="ui button ellipsis-button" aria-expanded="false">...</button>
+ <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button>
{{end}}
{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses "root" $}}
{{if IsMultilineCommitMessage .Message}}
diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl
index 6bbc19529f..57c9fd17ef 100644
--- a/templates/repo/commits_list_small.tmpl
+++ b/templates/repo/commits_list_small.tmpl
@@ -40,7 +40,7 @@
<span class="gt-mono commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.root.Context .Message ($.comment.Issue.PullRequest.BaseRepo.Link|Escape) $commitLink $.comment.Issue.PullRequest.BaseRepo.ComposeMetas}}</span>
{{if IsMultilineCommitMessage .Message}}
- <button class="ui button ellipsis-button" aria-expanded="false">...</button>
+ <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button>
{{end}}
{{if IsMultilineCommitMessage .Message}}
<pre class="commit-body gt-hidden">{{RenderCommitBody $.root.Context .Message ($.comment.Issue.PullRequest.BaseRepo.Link|Escape) $.comment.Issue.PullRequest.BaseRepo.ComposeMetas}}</pre>
diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl
index 13b4d3d3d3..3eabf9f181 100644
--- a/templates/repo/view_list.tmpl
+++ b/templates/repo/view_list.tmpl
@@ -28,7 +28,7 @@
{{$commitLink:= printf "%s/commit/%s" .RepoLink (PathEscape .LatestCommit.ID.String)}}
<span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{RenderCommitMessageLinkSubject $.Context .LatestCommit.Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span>
{{if IsMultilineCommitMessage .LatestCommit.Message}}
- <button class="ui button ellipsis-button" aria-expanded="false">...</button>
+ <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button>
<pre class="commit-body gt-hidden">{{RenderCommitBody $.Context .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}</pre>
{{end}}
</span>
diff --git a/web_src/js/features/repo-commit.js b/web_src/js/features/repo-commit.js
index 7e4e40806b..7240bf398a 100644
--- a/web_src/js/features/repo-commit.js
+++ b/web_src/js/features/repo-commit.js
@@ -5,7 +5,7 @@ import {toggleElem} from '../utils/dom.js';
const {csrfToken} = window.config;
export function initRepoEllipsisButton() {
- $('.ellipsis-button').on('click', function (e) {
+ $('.js-toggle-commit-body').on('click', function (e) {
e.preventDefault();
const expanded = $(this).attr('aria-expanded') === 'true';
toggleElem($(this).parent().find('.commit-body'));
diff --git a/web_src/js/features/repo-diff-commit.js b/web_src/js/features/repo-diff-commit.js
new file mode 100644
index 0000000000..968f318e63
--- /dev/null
+++ b/web_src/js/features/repo-diff-commit.js
@@ -0,0 +1,52 @@
+import {hideElem, showElem, toggleElem} from '../utils/dom.js';
+
+async function loadBranchesAndTags(area, loadingButton) {
+ loadingButton.classList.add('disabled');
+ try {
+ const res = await fetch(loadingButton.getAttribute('data-fetch-url'));
+ const data = await res.json();
+ hideElem(loadingButton);
+ addTags(area, data.tags);
+ addBranches(area, data.branches, data.default_branch);
+ showElem(area.querySelectorAll('.branch-and-tag-detail'));
+ } finally {
+ loadingButton.classList.remove('disabled');
+ }
+}
+
+function addTags(area, tags) {
+ const tagArea = area.querySelector('.tag-area');
+ toggleElem(tagArea, tags.length > 0);
+ for (const tag of tags) {
+ addLink(tagArea, tag.web_link, tag.name);
+ }
+}
+
+function addBranches(area, branches, defaultBranch) {
+ const defaultBranchTooltip = area.getAttribute('data-text-default-branch-tooltip');
+ const branchArea = area.querySelector('.branch-area');
+ toggleElem(branchArea, branches.length > 0);
+ for (const branch of branches) {
+ const tooltip = defaultBranch === branch.name ? defaultBranchTooltip : null;
+ addLink(branchArea, branch.web_link, branch.name, tooltip);
+ }
+}
+
+function addLink(parent, href, text, tooltip) {
+ const link = document.createElement('a');
+ link.classList.add('muted', 'gt-px-2');
+ link.href = href;
+ link.textContent = text;
+ if (tooltip) {
+ link.classList.add('gt-border-secondary', 'gt-rounded');
+ link.setAttribute('data-tooltip-content', tooltip);
+ }
+ parent.append(link);
+}
+
+export function initRepoDiffCommitBranchesAndTags() {
+ for (const area of document.querySelectorAll('.branch-and-tag-area')) {
+ const btn = area.querySelector('.load-branches-and-tags');
+ btn.addEventListener('click', () => loadBranchesAndTags(area, btn));
+ }
+}
diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js
index f23ff45470..5991df6322 100644
--- a/web_src/js/features/repo-legacy.js
+++ b/web_src/js/features/repo-legacy.js
@@ -459,7 +459,7 @@ async function onEditContent(event) {
}
export function initRepository() {
- if ($('.repository').length === 0) {
+ if ($('.page-content.repository').length === 0) {
return;
}
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 0c786f96fb..8bd219bbe1 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -83,6 +83,7 @@ import {initGiteaFomantic} from './modules/fomantic.js';
import {onDomReady} from './utils/dom.js';
import {initRepoIssueList} from './features/repo-issue-list.js';
import {initCommonIssueListQuickGoto} from './features/common-issue-list.js';
+import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js';
// Init Gitea's Fomantic settings
initGiteaFomantic();
@@ -141,6 +142,7 @@ onDomReady(() => {
initRepoCodeView();
initRepoCommentForm();
initRepoEllipsisButton();
+ initRepoDiffCommitBranchesAndTags();
initRepoCommitLastCommitLoader();
initRepoEditor();
initRepoGraphGit();