mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-03 00:01:21 -04:00
Compare commits
10 Commits
e58035d03a
...
5103bed55b
Author | SHA1 | Date | |
---|---|---|---|
|
5103bed55b | ||
|
6455c8202b | ||
|
97fc87af89 | ||
|
6fe5c4c4d9 | ||
|
97727a5e88 | ||
|
074f22c254 | ||
|
b12b135296 | ||
|
8415d77327 | ||
|
6183ed41fd | ||
|
3807b2f629 |
@ -119,11 +119,14 @@ type ContentsResponse struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
SHA string `json:"sha"`
|
||||
LastCommitSHA string `json:"last_commit_sha"`
|
||||
|
||||
LastCommitSHA *string `json:"last_commit_sha,omitempty"`
|
||||
// swagger:strfmt date-time
|
||||
LastCommitterDate time.Time `json:"last_committer_date"`
|
||||
LastCommitterDate *time.Time `json:"last_committer_date,omitempty"`
|
||||
// swagger:strfmt date-time
|
||||
LastAuthorDate time.Time `json:"last_author_date"`
|
||||
LastAuthorDate *time.Time `json:"last_author_date,omitempty"`
|
||||
LastCommitMessage *string `json:"last_commit_message,omitempty"`
|
||||
|
||||
// `type` will be `file`, `dir`, `symlink`, or `submodule`
|
||||
Type string `json:"type"`
|
||||
Size int64 `json:"size"`
|
||||
@ -141,8 +144,8 @@ type ContentsResponse struct {
|
||||
SubmoduleGitURL *string `json:"submodule_git_url"`
|
||||
Links *FileLinksResponse `json:"_links"`
|
||||
|
||||
LfsOid *string `json:"lfs_oid"`
|
||||
LfsSize *int64 `json:"lfs_size"`
|
||||
LfsOid *string `json:"lfs_oid,omitempty"`
|
||||
LfsSize *int64 `json:"lfs_size,omitempty"`
|
||||
}
|
||||
|
||||
// FileCommitResponse contains information generated from a Git commit for a repo's file.
|
||||
|
@ -1969,6 +1969,7 @@ pulls.cmd_instruction_checkout_title=Basculer
|
||||
pulls.cmd_instruction_checkout_desc=Depuis votre dépôt, basculer sur une nouvelle branche et tester des modifications.
|
||||
pulls.cmd_instruction_merge_title=Fusionner
|
||||
pulls.cmd_instruction_merge_desc=Fusionner les modifications et mettre à jour sur Gitea.
|
||||
pulls.cmd_instruction_merge_warning=Attention : cette opération ne peut pas fusionner la demande d’ajout car la « détection automatique de fusion manuelle » n’a pas été activée
|
||||
pulls.clear_merge_message=Effacer le message de fusion
|
||||
pulls.clear_merge_message_hint=Effacer le message de fusion ne supprimera que le message de la révision, mais pas les pieds de révision générés tels que "Co-Authored-By:".
|
||||
|
||||
@ -2768,6 +2769,8 @@ branch.new_branch_from=`Créer une nouvelle branche à partir de "%s"`
|
||||
branch.renamed=La branche %s à été renommée en %s.
|
||||
branch.rename_default_or_protected_branch_error=Seuls les administrateurs peuvent renommer les branches par défaut ou protégées.
|
||||
branch.rename_protected_branch_failed=Cette branche est protégée par des règles de protection basées sur des globs.
|
||||
branch.commits_divergence_from=Divergence de révisions : %[1]d en retard et %[2]d en avance sur %[3]s
|
||||
branch.commits_no_divergence=Identique à la branche %[1]s
|
||||
|
||||
tag.create_tag=Créer l'étiquette %s
|
||||
tag.create_tag_operation=Créer une étiquette
|
||||
|
@ -2769,6 +2769,8 @@ branch.new_branch_from=`Cruthaigh brainse nua ó "%s"`
|
||||
branch.renamed=Ainmníodh brainse %s go %s.
|
||||
branch.rename_default_or_protected_branch_error=Ní féidir ach le riarthóirí brainsí réamhshocraithe nó cosanta a athainmniú.
|
||||
branch.rename_protected_branch_failed=Tá an brainse seo faoi chosaint ag rialacha cosanta domhanda.
|
||||
branch.commits_divergence_from=Déanann sé dialltacht a thiomnú: %[1]d taobh thiar agus %[2]d chun tosaigh ar %[3]s
|
||||
branch.commits_no_divergence=Mar an gcéanna le brainse %[1]s
|
||||
|
||||
tag.create_tag=Cruthaigh clib %s
|
||||
tag.create_tag_operation=Cruthaigh clib
|
||||
|
@ -2769,6 +2769,8 @@ branch.new_branch_from=`Criar um novo ramo a partir do ramo "%s"`
|
||||
branch.renamed=O ramo %s foi renomeado para %s.
|
||||
branch.rename_default_or_protected_branch_error=Só os administradores é que podem renomear o ramo principal ou ramos protegidos.
|
||||
branch.rename_protected_branch_failed=Este ramo está protegido por regras de salvaguarda baseadas em padrões glob.
|
||||
branch.commits_divergence_from=Divergência nos cometimentos: %[1]d atrás e %[2]d à frente de %[3]s
|
||||
branch.commits_no_divergence=Idêntico ao ramo %[1]s
|
||||
|
||||
tag.create_tag=Criar etiqueta %s
|
||||
tag.create_tag_operation=Criar etiqueta
|
||||
|
@ -812,7 +812,8 @@ func GetContentsExt(ctx *context.APIContext) {
|
||||
// required: true
|
||||
// - name: filepath
|
||||
// in: path
|
||||
// description: path of the dir, file, symlink or submodule in the repo
|
||||
// description: path of the dir, file, symlink or submodule in the repo. Swagger requires path parameter to be "required",
|
||||
// you can leave it empty or pass a single dot (".") to get the root directory.
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: ref
|
||||
@ -823,7 +824,8 @@ func GetContentsExt(ctx *context.APIContext) {
|
||||
// - name: includes
|
||||
// in: query
|
||||
// description: By default this API's response only contains file's metadata. Use comma-separated "includes" options to retrieve more fields.
|
||||
// Option "file_content" will try to retrieve the file content, option "lfs_metadata" will try to retrieve LFS metadata.
|
||||
// Option "file_content" will try to retrieve the file content, "lfs_metadata" will try to retrieve LFS metadata,
|
||||
// "commit_metadata" will try to retrieve commit metadata, and "commit_message" will try to retrieve commit message.
|
||||
// type: string
|
||||
// required: false
|
||||
// responses:
|
||||
@ -832,6 +834,9 @@ func GetContentsExt(ctx *context.APIContext) {
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
if treePath := ctx.PathParam("*"); treePath == "." || treePath == "/" {
|
||||
ctx.SetPathParam("*", "") // workaround for swagger, it requires path parameter to be "required", but we need to list root directory
|
||||
}
|
||||
opts := files_service.GetContentsOrListOptions{TreePath: ctx.PathParam("*")}
|
||||
for includeOpt := range strings.SplitSeq(ctx.FormString("includes"), ",") {
|
||||
if includeOpt == "" {
|
||||
@ -842,6 +847,10 @@ func GetContentsExt(ctx *context.APIContext) {
|
||||
opts.IncludeSingleFileContent = true
|
||||
case "lfs_metadata":
|
||||
opts.IncludeLfsMetadata = true
|
||||
case "commit_metadata":
|
||||
opts.IncludeCommitMetadata = true
|
||||
case "commit_message":
|
||||
opts.IncludeCommitMessage = true
|
||||
default:
|
||||
ctx.APIError(http.StatusBadRequest, fmt.Sprintf("unknown include option %q", includeOpt))
|
||||
return
|
||||
@ -883,7 +892,11 @@ func GetContents(ctx *context.APIContext) {
|
||||
// "$ref": "#/responses/ContentsResponse"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
ret := getRepoContents(ctx, files_service.GetContentsOrListOptions{TreePath: ctx.PathParam("*"), IncludeSingleFileContent: true})
|
||||
ret := getRepoContents(ctx, files_service.GetContentsOrListOptions{
|
||||
TreePath: ctx.PathParam("*"),
|
||||
IncludeSingleFileContent: true,
|
||||
IncludeCommitMetadata: true,
|
||||
})
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ type GetContentsOrListOptions struct {
|
||||
TreePath string
|
||||
IncludeSingleFileContent bool // include the file's content when the tree path is a file
|
||||
IncludeLfsMetadata bool
|
||||
IncludeCommitMetadata bool
|
||||
IncludeCommitMessage bool
|
||||
}
|
||||
|
||||
// GetContentsOrList gets the metadata of a file's contents (*ContentsResponse) if treePath not a tree
|
||||
@ -132,6 +134,19 @@ func getFileContentsByEntryInternal(_ context.Context, repo *repo_model.Reposito
|
||||
}
|
||||
selfURLString := selfURL.String()
|
||||
|
||||
// All content types have these fields in populated
|
||||
contentsResponse := &api.ContentsResponse{
|
||||
Name: entry.Name(),
|
||||
Path: opts.TreePath,
|
||||
SHA: entry.ID.String(),
|
||||
Size: entry.Size(),
|
||||
URL: &selfURLString,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURLString,
|
||||
},
|
||||
}
|
||||
|
||||
if opts.IncludeCommitMetadata || opts.IncludeCommitMessage {
|
||||
err = gitRepo.AddLastCommitCache(repo.GetCommitsCountCacheKey(refCommit.InputRef, refType != git.RefTypeCommit), repo.FullName(), refCommit.CommitID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -142,29 +157,23 @@ func getFileContentsByEntryInternal(_ context.Context, repo *repo_model.Reposito
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// All content types have these fields in populated
|
||||
contentsResponse := &api.ContentsResponse{
|
||||
Name: entry.Name(),
|
||||
Path: opts.TreePath,
|
||||
SHA: entry.ID.String(),
|
||||
LastCommitSHA: lastCommit.ID.String(),
|
||||
Size: entry.Size(),
|
||||
URL: &selfURLString,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURLString,
|
||||
},
|
||||
}
|
||||
|
||||
if opts.IncludeCommitMetadata {
|
||||
contentsResponse.LastCommitSHA = util.ToPointer(lastCommit.ID.String())
|
||||
// GitHub doesn't have these fields in the response, but we could follow other similar APIs to name them
|
||||
// https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#list-commits
|
||||
if lastCommit.Committer != nil {
|
||||
contentsResponse.LastCommitterDate = lastCommit.Committer.When
|
||||
contentsResponse.LastCommitterDate = util.ToPointer(lastCommit.Committer.When)
|
||||
}
|
||||
if lastCommit.Author != nil {
|
||||
contentsResponse.LastAuthorDate = lastCommit.Author.When
|
||||
contentsResponse.LastAuthorDate = util.ToPointer(lastCommit.Author.When)
|
||||
}
|
||||
}
|
||||
if opts.IncludeCommitMessage {
|
||||
contentsResponse.LastCommitMessage = util.ToPointer(lastCommit.Message())
|
||||
}
|
||||
}
|
||||
|
||||
// Now populate the rest of the ContentsResponse based on entry type
|
||||
// Now populate the rest of the ContentsResponse based on the entry type
|
||||
if entry.IsRegular() || entry.IsExecutable() {
|
||||
contentsResponse.Type = string(ContentTypeRegular)
|
||||
// if it is listing the repo root dir, don't waste system resources on reading content
|
||||
|
@ -5,56 +5,21 @@ package files
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
|
||||
_ "code.gitea.io/gitea/models/actions"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
func getExpectedReadmeContentsResponse() *api.ContentsResponse {
|
||||
treePath := "README.md"
|
||||
sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
|
||||
encoding := "base64"
|
||||
content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x"
|
||||
selfURL := "https://try.gitea.io/api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master"
|
||||
htmlURL := "https://try.gitea.io/user2/repo1/src/branch/master/" + treePath
|
||||
gitURL := "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/" + sha
|
||||
downloadURL := "https://try.gitea.io/user2/repo1/raw/branch/master/" + treePath
|
||||
return &api.ContentsResponse{
|
||||
Name: treePath,
|
||||
Path: treePath,
|
||||
SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
|
||||
LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
|
||||
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
|
||||
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
|
||||
Type: "file",
|
||||
Size: 30,
|
||||
Encoding: &encoding,
|
||||
Content: &content,
|
||||
URL: &selfURL,
|
||||
HTMLURL: &htmlURL,
|
||||
GitURL: &gitURL,
|
||||
DownloadURL: &downloadURL,
|
||||
Links: &api.FileLinksResponse{
|
||||
Self: &selfURL,
|
||||
GitURL: &gitURL,
|
||||
HTMLURL: &htmlURL,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetContents(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
@ -63,45 +28,8 @@ func TestGetContents(t *testing.T) {
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo, gitRepo := ctx.Repo.Repository, ctx.Repo.GitRepo
|
||||
refCommit, err := utils.ResolveRefCommit(ctx, ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("GetContentsOrList(README.md)-MetaOnly", func(t *testing.T) {
|
||||
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
||||
expectedContentsResponse.Encoding = nil // because will be in a list, doesn't have encoding and content
|
||||
expectedContentsResponse.Content = nil
|
||||
extResp, err := GetContentsOrList(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{TreePath: "README.md", IncludeSingleFileContent: false})
|
||||
assert.Equal(t, expectedContentsResponse, extResp.FileContents)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetContentsOrList(README.md)", func(t *testing.T) {
|
||||
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
||||
extResp, err := GetContentsOrList(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{TreePath: "README.md", IncludeSingleFileContent: true})
|
||||
assert.Equal(t, expectedContentsResponse, extResp.FileContents)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetContentsOrList(RootDir)", func(t *testing.T) {
|
||||
readmeContentsResponse := getExpectedReadmeContentsResponse()
|
||||
readmeContentsResponse.Encoding = nil // because will be in a list, doesn't have encoding and content
|
||||
readmeContentsResponse.Content = nil
|
||||
expectedContentsListResponse := []*api.ContentsResponse{readmeContentsResponse}
|
||||
// even if IncludeFileContent is true, it has no effect for directory listing
|
||||
extResp, err := GetContentsOrList(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{TreePath: "", IncludeSingleFileContent: true})
|
||||
assert.Equal(t, expectedContentsListResponse, extResp.DirContents)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("GetContentsOrList(NoSuchTreePath)", func(t *testing.T) {
|
||||
extResp, err := GetContentsOrList(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{TreePath: "no-such/file.md"})
|
||||
assert.Error(t, err)
|
||||
assert.EqualError(t, err, "object does not exist [id: , rel_path: no-such]")
|
||||
assert.Nil(t, extResp.DirContents)
|
||||
assert.Nil(t, extResp.FileContents)
|
||||
})
|
||||
// GetContentsOrList's behavior is fully tested in integration tests, so we don't need to test it here.
|
||||
|
||||
t.Run("GetBlobBySHA", func(t *testing.T) {
|
||||
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
||||
|
@ -22,7 +22,12 @@ import (
|
||||
func GetContentsListFromTreePaths(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, treePaths []string) (files []*api.ContentsResponse) {
|
||||
var size int64
|
||||
for _, treePath := range treePaths {
|
||||
fileContents, _ := GetFileContents(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{TreePath: treePath, IncludeSingleFileContent: true}) // ok if fails, then will be nil
|
||||
// ok if fails, then will be nil
|
||||
fileContents, _ := GetFileContents(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{
|
||||
TreePath: treePath,
|
||||
IncludeSingleFileContent: true,
|
||||
IncludeCommitMetadata: true,
|
||||
})
|
||||
if fileContents != nil && fileContents.Content != nil && *fileContents.Content != "" {
|
||||
// if content isn't empty (e.g., due to the single blob being too large), add file size to response size
|
||||
size += int64(len(*fileContents.Content))
|
||||
|
@ -29,7 +29,7 @@ export default {
|
||||
important: true, // the frameworks are mixed together, so tailwind needs to override other framework's styles
|
||||
content: [
|
||||
isProduction && '!./templates/devtest/**/*',
|
||||
isProduction && '!./web_src/js/standalone/devtest.js',
|
||||
isProduction && '!./web_src/js/standalone/devtest.ts',
|
||||
'!./templates/swagger/v1_json.tmpl',
|
||||
'!./templates/user/auth/oidc_wellknown.tmpl',
|
||||
'!**/*_test.go',
|
||||
|
@ -1,44 +1,10 @@
|
||||
<div class="ui attached table segment commit-table">
|
||||
<table class="ui very basic striped table unstackable" id="commits-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th>
|
||||
<th class="two wide sha">{{StringUtils.ToUpper $.Repository.ObjectFormatName}}</th>
|
||||
<th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th>
|
||||
<th class="two wide tw-text-right">{{ctx.Locale.Tr "repo.commits.date"}}</th>
|
||||
<th class="one wide"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="commit-list">
|
||||
<div class="flex-list">
|
||||
{{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}}
|
||||
{{range .Commits}}
|
||||
<tr>
|
||||
<td class="author">
|
||||
<div class="tw-flex">
|
||||
{{$userName := .Author.Name}}
|
||||
{{if .User}}
|
||||
{{if and .User.FullName DefaultShowFullName}}
|
||||
{{$userName = .User.FullName}}
|
||||
{{end}}
|
||||
{{ctx.AvatarUtils.Avatar .User 28 "tw-mr-2"}}<a class="muted author-wrapper" href="{{.User.HomeLink}}">{{$userName}}</a>
|
||||
{{else}}
|
||||
{{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}}
|
||||
<span class="author-wrapper">{{$userName}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
<td class="sha">
|
||||
{{$commitBaseLink := ""}}
|
||||
{{if $.PageIsWiki}}
|
||||
{{$commitBaseLink = printf "%s/wiki/commit" $commitRepoLink}}
|
||||
{{else if $.PageIsPullCommits}}
|
||||
{{$commitBaseLink = printf "%s/pulls/%d/commits" $commitRepoLink $.Issue.Index}}
|
||||
{{else if $.Reponame}}
|
||||
{{$commitBaseLink = printf "%s/commit" $commitRepoLink}}
|
||||
{{end}}
|
||||
{{template "repo/commit_sign_badge" dict "Commit" . "CommitBaseLink" $commitBaseLink "CommitSignVerification" .Verification}}
|
||||
</td>
|
||||
<td class="message">
|
||||
<div class="flex-item tw-p-2 tw-items-center">
|
||||
<div class="flex-item-main">
|
||||
<div class="flex-item-title">
|
||||
<span class="message-wrapper">
|
||||
{{if $.PageIsWiki}}
|
||||
<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | ctx.RenderUtils.RenderEmoji}}</span>
|
||||
@ -50,22 +16,47 @@
|
||||
{{if IsMultilineCommitMessage .Message}}
|
||||
<button class="ui button ellipsis-button" aria-expanded="false" data-global-click="onRepoEllipsisButtonClick">...</button>
|
||||
{{end}}
|
||||
{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}}
|
||||
{{if IsMultilineCommitMessage .Message}}
|
||||
<pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .Message $.Repository}}</pre>
|
||||
<div class="sha">
|
||||
{{$commitBaseLink := ""}}
|
||||
{{if $.PageIsWiki}}
|
||||
{{$commitBaseLink = printf "%s/wiki/commit" $commitRepoLink}}
|
||||
{{else if $.PageIsPullCommits}}
|
||||
{{$commitBaseLink = printf "%s/pulls/%d/commits" $commitRepoLink $.Issue.Index}}
|
||||
{{else if $.Reponame}}
|
||||
{{$commitBaseLink = printf "%s/commit" $commitRepoLink}}
|
||||
{{end}}
|
||||
{{template "repo/commit_sign_badge" dict "Commit" . "CommitBaseLink" $commitBaseLink "CommitSignVerification" .Verification}}
|
||||
</div>
|
||||
{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}}
|
||||
{{if $.CommitsTagsMap}}
|
||||
{{range (index $.CommitsTagsMap .ID.String)}}
|
||||
{{- template "repo/tag/name" dict "RepoLink" $.Repository.Link "TagName" .TagName "IsRelease" (not .IsTag) -}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</td>
|
||||
{{if .Committer}}
|
||||
<td class="tw-text-right">{{DateUtils.TimeSince .Committer.When}}</td>
|
||||
{{else}}
|
||||
<td class="tw-text-right">{{DateUtils.TimeSince .Author.When}}</td>
|
||||
</div>
|
||||
{{if IsMultilineCommitMessage .Message}}
|
||||
<pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .Message $.Repository}}</pre>
|
||||
{{end}}
|
||||
<td class="tw-text-right tw-py-0">
|
||||
<div class="flex-item-body">
|
||||
{{$userName := .Author.Name}}
|
||||
{{if .User}}
|
||||
{{if and .User.FullName DefaultShowFullName}}
|
||||
{{$userName = .User.FullName}}
|
||||
{{end}}
|
||||
{{ctx.AvatarUtils.Avatar .User 20}}
|
||||
<a class="muted author-wrapper" href="{{.User.HomeLink}}">{{$userName}}</a>
|
||||
{{else}}
|
||||
{{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}}
|
||||
<span class="author-wrapper">{{$userName}}</span>
|
||||
{{end}}
|
||||
{{if .Committer}}
|
||||
{{DateUtils.TimeSince .Committer.When}}
|
||||
{{else}}
|
||||
{{DateUtils.TimeSince .Author.When}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-item-trailing">
|
||||
<button class="btn interact-bg tw-p-2 copy-commit-id" data-tooltip-content="{{ctx.Locale.Tr "copy_hash"}}" data-clipboard-text="{{.ID}}">{{svg "octicon-copy"}}</button>
|
||||
{{/* at the moment, wiki doesn't support these "view" links like "view at history point" */}}
|
||||
{{if not $.PageIsWiki}}
|
||||
@ -81,9 +72,8 @@
|
||||
{{if $.FileTreePath}}{{$viewCommitLink = printf "%s/%s" $viewCommitLink (PathEscapeSegments $.FileTreePath)}}{{end}}
|
||||
<a class="btn interact-bg tw-p-2 view-commit-path" data-tooltip-content="{{ctx.Locale.Tr "repo.commits.view_path"}}" href="{{$viewCommitLink}}">{{svg "octicon-file-code"}}</a>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
8
templates/swagger/v1_json.tmpl
generated
8
templates/swagger/v1_json.tmpl
generated
@ -7547,7 +7547,7 @@
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "path of the dir, file, symlink or submodule in the repo",
|
||||
"description": "path of the dir, file, symlink or submodule in the repo. Swagger requires path parameter to be \"required\", you can leave it empty or pass a single dot (\".\") to get the root directory.",
|
||||
"name": "filepath",
|
||||
"in": "path",
|
||||
"required": true
|
||||
@ -7560,7 +7560,7 @@
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "By default this API's response only contains file's metadata. Use comma-separated \"includes\" options to retrieve more fields. Option \"file_content\" will try to retrieve the file content, option \"lfs_metadata\" will try to retrieve LFS metadata.",
|
||||
"description": "By default this API's response only contains file's metadata. Use comma-separated \"includes\" options to retrieve more fields. Option \"file_content\" will try to retrieve the file content, \"lfs_metadata\" will try to retrieve LFS metadata, \"commit_metadata\" will try to retrieve commit metadata, and \"commit_message\" will try to retrieve commit message.",
|
||||
"name": "includes",
|
||||
"in": "query"
|
||||
}
|
||||
@ -22368,6 +22368,10 @@
|
||||
"format": "date-time",
|
||||
"x-go-name": "LastAuthorDate"
|
||||
},
|
||||
"last_commit_message": {
|
||||
"type": "string",
|
||||
"x-go-name": "LastCommitMessage"
|
||||
},
|
||||
"last_commit_sha": {
|
||||
"type": "string",
|
||||
"x-go-name": "LastCommitSHA"
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -52,8 +53,8 @@ func getCreateFileOptions() api.CreateFileOptions {
|
||||
func normalizeFileContentResponseCommitTime(c *api.ContentsResponse) {
|
||||
// decoded JSON response may contain different timezone from the one parsed by git commit
|
||||
// so we need to normalize the time to UTC to make "assert.Equal" pass
|
||||
c.LastCommitterDate = c.LastCommitterDate.UTC()
|
||||
c.LastAuthorDate = c.LastAuthorDate.UTC()
|
||||
c.LastCommitterDate = util.ToPointer(c.LastCommitterDate.UTC())
|
||||
c.LastAuthorDate = util.ToPointer(c.LastAuthorDate.UTC())
|
||||
}
|
||||
|
||||
type apiFileResponseInfo struct {
|
||||
@ -74,9 +75,9 @@ func getExpectedFileResponseForCreate(info apiFileResponseInfo) *api.FileRespons
|
||||
Name: path.Base(info.treePath),
|
||||
Path: info.treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: info.lastCommitSHA,
|
||||
LastCommitterDate: info.lastCommitterWhen,
|
||||
LastAuthorDate: info.lastAuthorWhen,
|
||||
LastCommitSHA: util.ToPointer(info.lastCommitSHA),
|
||||
LastCommitterDate: util.ToPointer(info.lastCommitterWhen),
|
||||
LastAuthorDate: util.ToPointer(info.lastAuthorWhen),
|
||||
Size: 16,
|
||||
Type: "file",
|
||||
Encoding: &encoding,
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -60,9 +61,9 @@ func getExpectedFileResponseForUpdate(info apiFileResponseInfo) *api.FileRespons
|
||||
Name: path.Base(info.treePath),
|
||||
Path: info.treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: info.lastCommitSHA,
|
||||
LastCommitterDate: info.lastCommitterWhen,
|
||||
LastAuthorDate: info.lastAuthorWhen,
|
||||
LastCommitSHA: util.ToPointer(info.lastCommitSHA),
|
||||
LastCommitterDate: util.ToPointer(info.lastCommitterWhen),
|
||||
LastAuthorDate: util.ToPointer(info.lastAuthorWhen),
|
||||
Type: "file",
|
||||
Size: 20,
|
||||
Encoding: &encoding,
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -35,9 +36,9 @@ func getExpectedContentsListResponseForContents(ref, refType, lastCommitSHA stri
|
||||
Name: path.Base(treePath),
|
||||
Path: treePath,
|
||||
SHA: sha,
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
|
||||
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
|
||||
LastCommitSHA: util.ToPointer(lastCommitSHA),
|
||||
LastCommitterDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
|
||||
LastAuthorDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
|
||||
Type: "file",
|
||||
Size: 30,
|
||||
URL: &selfURL,
|
||||
@ -65,7 +66,6 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
|
||||
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
|
||||
treePath := "" // root dir
|
||||
|
||||
// Get user2's token
|
||||
session := loginUser(t, user2.Name)
|
||||
@ -94,7 +94,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
// ref is default ref
|
||||
ref := repo1.DefaultBranch
|
||||
refType := "branch"
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents?ref=%s", user2.Name, repo1.Name, ref)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var contentsListResponse []*api.ContentsResponse
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
@ -106,7 +106,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
|
||||
// No ref
|
||||
refType = "branch"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", user2.Name, repo1.Name)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
@ -117,7 +117,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
// ref is the branch we created above in setup
|
||||
ref = newBranch
|
||||
refType = "branch"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents?ref=%s", user2.Name, repo1.Name, ref)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
@ -131,7 +131,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
// ref is the new tag we created above in setup
|
||||
ref = newTag
|
||||
refType = "tag"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/?ref=%s", user2.Name, repo1.Name, ref)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
@ -145,7 +145,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
// ref is a commit
|
||||
ref = commitID
|
||||
refType = "commit"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/?ref=%s", user2.Name, repo1.Name, ref)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &contentsListResponse)
|
||||
assert.NotNil(t, contentsListResponse)
|
||||
@ -154,21 +154,21 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
|
||||
|
||||
// Test file contents a file with a bad ref
|
||||
ref = "badref"
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/?ref=%s", user2.Name, repo1.Name, ref)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test accessing private ref with user token that does not have access - should fail
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath).
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", user2.Name, repo16.Name).
|
||||
AddTokenAuth(token4)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// Test access private ref of owner of token
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md", user2.Name, repo16.Name).
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", user2.Name, repo16.Name).
|
||||
AddTokenAuth(token2)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// Test access of org org3 private repo file by owner user2
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", org3.Name, repo3.Name, treePath).
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", org3.Name, repo3.Name).
|
||||
AddTokenAuth(token2)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
@ -35,9 +35,9 @@ func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string)
|
||||
Name: treePath,
|
||||
Path: treePath,
|
||||
SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
|
||||
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
|
||||
LastCommitSHA: util.ToPointer(lastCommitSHA),
|
||||
LastCommitterDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
|
||||
LastAuthorDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
|
||||
Type: "file",
|
||||
Size: 30,
|
||||
Encoding: util.ToPointer("base64"),
|
||||
@ -97,11 +97,16 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
|
||||
require.NoError(t, err)
|
||||
/*** END SETUP ***/
|
||||
|
||||
// not found
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/no-such/file.md", user2.Name, repo1.Name)
|
||||
resp := MakeRequest(t, req, http.StatusNotFound)
|
||||
assert.Contains(t, resp.Body.String(), "object does not exist [id: , rel_path: no-such]")
|
||||
|
||||
// ref is default ref
|
||||
ref := repo1.DefaultBranch
|
||||
refType := "branch"
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
var contentsResponse api.ContentsResponse
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
lastCommit, _ := gitRepo.GetCommitByPath("README.md")
|
||||
@ -206,14 +211,30 @@ func testAPIGetContentsExt(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
token2 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
t.Run("DirContents", func(t *testing.T) {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs?ref=sub-home-md-img-check")
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext?ref=sub-home-md-img-check")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var contentsResponse api.ContentsExtResponse
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.Nil(t, contentsResponse.FileContents)
|
||||
assert.NotNil(t, contentsResponse.DirContents)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/.?ref=sub-home-md-img-check")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
contentsResponse = api.ContentsExtResponse{}
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.Nil(t, contentsResponse.FileContents)
|
||||
assert.NotNil(t, contentsResponse.DirContents)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs?ref=sub-home-md-img-check")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
contentsResponse = api.ContentsExtResponse{}
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
assert.Nil(t, contentsResponse.FileContents)
|
||||
assert.Equal(t, "README.md", contentsResponse.DirContents[0].Name)
|
||||
assert.Nil(t, contentsResponse.DirContents[0].Encoding)
|
||||
assert.Nil(t, contentsResponse.DirContents[0].Content)
|
||||
assert.Nil(t, contentsResponse.DirContents[0].LastCommitSHA)
|
||||
assert.Nil(t, contentsResponse.DirContents[0].LastCommitMessage)
|
||||
|
||||
// "includes=file_content" shouldn't affect directory listing
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs?ref=sub-home-md-img-check&includes=file_content")
|
||||
@ -240,7 +261,7 @@ func testAPIGetContentsExt(t *testing.T) {
|
||||
assert.Equal(t, util.ToPointer("0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351"), respFile.LfsOid)
|
||||
})
|
||||
t.Run("FileContents", func(t *testing.T) {
|
||||
// by default, no file content is returned
|
||||
// by default, no file content or commit info is returned
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs/README.md?ref=sub-home-md-img-check")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
var contentsResponse api.ContentsExtResponse
|
||||
@ -249,9 +270,11 @@ func testAPIGetContentsExt(t *testing.T) {
|
||||
assert.Equal(t, "README.md", contentsResponse.FileContents.Name)
|
||||
assert.Nil(t, contentsResponse.FileContents.Encoding)
|
||||
assert.Nil(t, contentsResponse.FileContents.Content)
|
||||
assert.Nil(t, contentsResponse.FileContents.LastCommitSHA)
|
||||
assert.Nil(t, contentsResponse.FileContents.LastCommitMessage)
|
||||
|
||||
// file content is only returned when `includes=file_content`
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs/README.md?ref=sub-home-md-img-check&includes=file_content")
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs/README.md?ref=sub-home-md-img-check&includes=file_content,commit_metadata,commit_message")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
contentsResponse = api.ContentsExtResponse{}
|
||||
DecodeJSON(t, resp, &contentsResponse)
|
||||
@ -259,6 +282,8 @@ func testAPIGetContentsExt(t *testing.T) {
|
||||
assert.Equal(t, "README.md", contentsResponse.FileContents.Name)
|
||||
assert.NotNil(t, contentsResponse.FileContents.Encoding)
|
||||
assert.NotNil(t, contentsResponse.FileContents.Content)
|
||||
assert.Equal(t, "4649299398e4d39a5c09eb4f534df6f1e1eb87cc", *contentsResponse.FileContents.LastCommitSHA)
|
||||
assert.Equal(t, "Test how READMEs render images when found in a subfolder\n", *contentsResponse.FileContents.LastCommitMessage)
|
||||
|
||||
req = NewRequestf(t, "GET", "/api/v1/repos/user2/lfs/contents-ext/jpeg.jpg?includes=file_content").AddTokenAuth(token2)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
@ -270,6 +295,8 @@ func testAPIGetContentsExt(t *testing.T) {
|
||||
assert.Equal(t, "jpeg.jpg", respFile.Name)
|
||||
assert.NotNil(t, respFile.Encoding)
|
||||
assert.NotNil(t, respFile.Content)
|
||||
assert.Nil(t, contentsResponse.FileContents.LastCommitSHA)
|
||||
assert.Nil(t, contentsResponse.FileContents.LastCommitMessage)
|
||||
assert.Equal(t, util.ToPointer(int64(107)), respFile.LfsSize)
|
||||
assert.Equal(t, util.ToPointer("0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351"), respFile.LfsOid)
|
||||
})
|
||||
|
@ -708,7 +708,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
// Get first commit URL
|
||||
commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
|
||||
commitURL, exists := doc.doc.Find(".commit-table .flex-list .flex-item .sha a").Last().Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
|
@ -50,7 +50,7 @@ func TestPullCreate_CommitStatus(t *testing.T) {
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
// Get first commit URL
|
||||
commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
|
||||
commitURL, exists := doc.doc.Find(".commit-table .flex-list .flex-item .sha a").Last().Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
@ -88,12 +88,12 @@ func TestPullCreate_CommitStatus(t *testing.T) {
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
|
||||
commitURL, exists = doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
|
||||
commitURL, exists = doc.doc.Find(".commit-table .flex-list .flex-item .sha a").Last().Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
assert.Equal(t, commitID, path.Base(commitURL))
|
||||
|
||||
cls, ok := doc.doc.Find("#commits-table tbody tr td.message .commit-status").Last().Attr("class")
|
||||
cls, ok := doc.doc.Find(".commit-table .flex-list .flex-item .flex-item-title .commit-status").Last().Attr("class")
|
||||
assert.True(t, ok)
|
||||
assert.Contains(t, cls, statesIcons[status])
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func testRepoCommitsSearch(t *testing.T, query, commit string) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
sel := doc.doc.Find("#commits-table tbody tr td.sha a")
|
||||
sel := doc.doc.Find(".commit-table .flex-list .flex-item .sha a")
|
||||
assert.Equal(t, commit, strings.TrimSpace(sel.Text()))
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ func TestRepoCommits(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
|
||||
commitURL, exists := doc.doc.Find(".commit-table .commit-id-short").Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
}
|
||||
@ -45,14 +45,14 @@ func Test_ReposGitCommitListNotMaster(t *testing.T) {
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
var commits []string
|
||||
doc.doc.Find("#commits-table .commit-id-short").Each(func(i int, s *goquery.Selection) {
|
||||
doc.doc.Find(".commit-table .commit-id-short").Each(func(i int, s *goquery.Selection) {
|
||||
commitURL, _ := s.Attr("href")
|
||||
commits = append(commits, path.Base(commitURL))
|
||||
})
|
||||
assert.Equal(t, []string{"69554a64c1e6030f051e5c3f94bfbd773cd6a324", "27566bd5738fc8b4e3fef3c5e72cce608537bd95", "5099b81332712fe655e34e8dd63574f503f61811"}, commits)
|
||||
|
||||
var userHrefs []string
|
||||
doc.doc.Find("#commits-table .author-wrapper").Each(func(i int, s *goquery.Selection) {
|
||||
doc.doc.Find(".commit-table .author-wrapper").Each(func(i int, s *goquery.Selection) {
|
||||
userHref, _ := s.Attr("href")
|
||||
userHrefs = append(userHrefs, userHref)
|
||||
})
|
||||
@ -70,7 +70,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
// Get first commit URL
|
||||
commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
|
||||
commitURL, exists := doc.doc.Find(".commit-table .commit-id-short").Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
@ -88,7 +88,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
||||
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
// Check if commit status is displayed in message column (.tippy-target to ignore the tippy trigger)
|
||||
sel := doc.doc.Find("#commits-table .message .tippy-target .commit-status")
|
||||
sel := doc.doc.Find(".commit-table .flex-item-title .tippy-target .commit-status")
|
||||
assert.Equal(t, 1, sel.Length())
|
||||
for _, class := range classes {
|
||||
assert.True(t, sel.HasClass(class))
|
||||
@ -164,7 +164,7 @@ func TestRepoCommitsStatusParallel(t *testing.T) {
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
// Get first commit URL
|
||||
commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
|
||||
commitURL, exists := doc.doc.Find(".commit-table .commit-id-short").Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
@ -199,7 +199,7 @@ func TestRepoCommitsStatusMultiple(t *testing.T) {
|
||||
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
// Get first commit URL
|
||||
commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
|
||||
commitURL, exists := doc.doc.Find(".commit-table .commit-id-short").Attr("href")
|
||||
assert.True(t, exists)
|
||||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
@ -224,6 +224,6 @@ func TestRepoCommitsStatusMultiple(t *testing.T) {
|
||||
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
// Check that the data-global-init="initCommitStatuses" (for trigger) and commit-status (svg) are present
|
||||
sel := doc.doc.Find(`#commits-table .message [data-global-init="initCommitStatuses"] .commit-status`)
|
||||
sel := doc.doc.Find(`.commit-table .flex-list .flex-item .flex-item-title [data-global-init="initCommitStatuses"] .commit-status`)
|
||||
assert.Equal(t, 1, sel.Length())
|
||||
}
|
||||
|
@ -155,9 +155,9 @@ func getExpectedFileResponseForRepoFilesCreate(commitID string, lastCommit *git.
|
||||
Name: path.Base(treePath),
|
||||
Path: treePath,
|
||||
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
|
||||
LastCommitSHA: lastCommit.ID.String(),
|
||||
LastCommitterDate: lastCommit.Committer.When,
|
||||
LastAuthorDate: lastCommit.Author.When,
|
||||
LastCommitSHA: util.ToPointer(lastCommit.ID.String()),
|
||||
LastCommitterDate: util.ToPointer(lastCommit.Committer.When),
|
||||
LastAuthorDate: util.ToPointer(lastCommit.Author.When),
|
||||
Type: "file",
|
||||
Size: 18,
|
||||
Encoding: &encoding,
|
||||
@ -198,7 +198,7 @@ func getExpectedFileResponseForRepoFilesCreate(commitID string, lastCommit *git.
|
||||
SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
|
||||
},
|
||||
},
|
||||
Message: "Updates README.md\n",
|
||||
Message: "Creates new/file.txt\n",
|
||||
Tree: &api.CommitMeta{
|
||||
URL: setting.AppURL + "api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
|
||||
SHA: "f93e3a1a1525fb5b91020git dda86e44810c87a2d7bc",
|
||||
@ -225,9 +225,9 @@ func getExpectedFileResponseForRepoFilesUpdate(commitID, filename, lastCommitSHA
|
||||
Name: filename,
|
||||
Path: filename,
|
||||
SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647",
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
LastCommitterDate: lastCommitterWhen,
|
||||
LastAuthorDate: lastAuthorWhen,
|
||||
LastCommitSHA: util.ToPointer(lastCommitSHA),
|
||||
LastCommitterDate: util.ToPointer(lastCommitterWhen),
|
||||
LastAuthorDate: util.ToPointer(lastAuthorWhen),
|
||||
Type: "file",
|
||||
Size: 43,
|
||||
Encoding: &encoding,
|
||||
@ -331,7 +331,7 @@ func getExpectedFileResponseForRepoFilesUpdateRename(commitID, lastCommitSHA str
|
||||
Name: detail.filename,
|
||||
Path: detail.filename,
|
||||
SHA: detail.sha,
|
||||
LastCommitSHA: lastCommitSHA,
|
||||
LastCommitSHA: util.ToPointer(lastCommitSHA),
|
||||
Type: "file",
|
||||
Size: detail.size,
|
||||
Encoding: util.ToPointer("base64"),
|
||||
@ -537,7 +537,7 @@ func TestChangeRepoFilesForUpdateWithFileRename(t *testing.T) {
|
||||
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
|
||||
expectedFileResponse := getExpectedFileResponseForRepoFilesUpdateRename(commit.ID.String(), lastCommit.ID.String())
|
||||
for _, file := range filesResponse.Files {
|
||||
file.LastCommitterDate, file.LastAuthorDate = time.Time{}, time.Time{} // there might be different time in one operation, so we ignore them
|
||||
file.LastCommitterDate, file.LastAuthorDate = nil, nil // there might be different time in one operation, so we ignore them
|
||||
}
|
||||
assert.Len(t, filesResponse.Files, 4)
|
||||
assert.Equal(t, expectedFileResponse.Files, filesResponse.Files)
|
||||
|
@ -36,9 +36,9 @@ func TestCommitListActions(t *testing.T) {
|
||||
req := NewRequest(t, "GET", "/user2/repo1/wiki/Home?action=_revision")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
AssertHTMLElement(t, htmlDoc, ".commit-list .copy-commit-id", true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, false)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, false)
|
||||
AssertHTMLElement(t, htmlDoc, ".commit-table .copy-commit-id", true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .view-single-diff`, false)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .view-commit-path`, false)
|
||||
})
|
||||
|
||||
t.Run("RepoCommitList", func(t *testing.T) {
|
||||
@ -48,9 +48,9 @@ func TestCommitListActions(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .copy-commit-id`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, false)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .copy-commit-id`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .view-single-diff`, false)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .view-commit-path`, true)
|
||||
})
|
||||
|
||||
t.Run("RepoFileHistory", func(t *testing.T) {
|
||||
@ -60,8 +60,8 @@ func TestCommitListActions(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .copy-commit-id`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .copy-commit-id`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .view-single-diff`, true)
|
||||
AssertHTMLElement(t, htmlDoc, `.commit-table .view-commit-path`, true)
|
||||
})
|
||||
}
|
||||
|
@ -572,12 +572,6 @@ td .commit-summary {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.repository.view.issue .comment-list .timeline-item.event > .commit-status-link {
|
||||
float: right;
|
||||
margin-right: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.repository.view.issue .comment-list .timeline-item .comparebox {
|
||||
line-height: 32px;
|
||||
vertical-align: middle;
|
||||
@ -878,17 +872,6 @@ td .commit-summary {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.repository #commits-table td:not(.message) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.repository #commits-table thead .sha {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) {
|
||||
background-color: var(--color-light) !important;
|
||||
}
|
||||
|
||||
.repository .data-table {
|
||||
width: 100%;
|
||||
}
|
||||
@ -1541,10 +1524,6 @@ td .commit-summary {
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
tbody.commit-list {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.message-wrapper,
|
||||
.author-wrapper {
|
||||
overflow: hidden;
|
||||
@ -1564,44 +1543,12 @@ tbody.commit-list {
|
||||
max-width: calc(100% - 2.5rem);
|
||||
}
|
||||
|
||||
/* in the commit list, messages can wrap so we can use inline */
|
||||
.commit-list .message-wrapper {
|
||||
display: inline;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
tr.commit-list {
|
||||
width: 100%;
|
||||
}
|
||||
.author-wrapper {
|
||||
max-width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 991.98px) {
|
||||
tr.commit-list {
|
||||
width: 723px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) and (max-width: 1200px) {
|
||||
tr.commit-list {
|
||||
width: 933px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1201px) {
|
||||
tr.commit-list {
|
||||
width: 1127px;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-list .commit-status-link {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.commit-body {
|
||||
margin: 0.25em 0;
|
||||
white-space: pre-wrap;
|
||||
@ -2010,10 +1957,6 @@ tbody.commit-list {
|
||||
.commit-table {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.commit-table td.sha,
|
||||
.commit-table th.sha {
|
||||
display: none !important;
|
||||
}
|
||||
.comment-header {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export function initRepoEllipsisButton() {
|
||||
registerGlobalEventFunc('click', 'onRepoEllipsisButtonClick', async (el: HTMLInputElement, e: Event) => {
|
||||
e.preventDefault();
|
||||
const expanded = el.getAttribute('aria-expanded') === 'true';
|
||||
toggleElem(el.parentElement.querySelector('.commit-body'));
|
||||
toggleElem(el.parentElement.parentElement.querySelector('.commit-body'));
|
||||
el.setAttribute('aria-expanded', String(!expanded));
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user