mirror of https://github.com/go-gitea/gitea.git
Merge branch 'main' into fix-obj-hash
This commit is contained in:
commit
2fad316df7
|
@ -74,6 +74,13 @@ func (run *ActionRun) Link() string {
|
|||
return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.Index)
|
||||
}
|
||||
|
||||
func (run *ActionRun) WorkflowLink() string {
|
||||
if run.Repo == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s/actions/?workflow=%s", run.Repo.Link(), run.WorkflowID)
|
||||
}
|
||||
|
||||
// RefLink return the url of run's ref
|
||||
func (run *ActionRun) RefLink() string {
|
||||
refName := git.RefName(run.Ref)
|
||||
|
@ -156,6 +163,10 @@ func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, err
|
|||
return nil, fmt.Errorf("event %s is not a pull request event", run.Event)
|
||||
}
|
||||
|
||||
func (run *ActionRun) IsSchedule() bool {
|
||||
return run.ScheduleID > 0
|
||||
}
|
||||
|
||||
func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error {
|
||||
_, err := db.GetEngine(ctx).ID(repo.ID).
|
||||
SetExpr("num_action_runs",
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
)
|
||||
|
||||
// LFSResult represents commits found using a provided pointer file hash
|
||||
type LFSResult struct {
|
||||
Name string
|
||||
SHA string
|
||||
Summary string
|
||||
When time.Time
|
||||
ParentHashes []git.ObjectID
|
||||
BranchName string
|
||||
FullCommitName string
|
||||
}
|
||||
|
||||
type lfsResultSlice []*LFSResult
|
||||
|
||||
func (a lfsResultSlice) Len() int { return len(a) }
|
||||
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
|
||||
|
||||
func lfsError(msg string, err error) error {
|
||||
return fmt.Errorf("LFS error occurred, %s: err: %w", msg, err)
|
||||
}
|
|
@ -7,12 +7,10 @@ package pipeline
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
|
||||
|
@ -21,23 +19,6 @@ import (
|
|||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// LFSResult represents commits found using a provided pointer file hash
|
||||
type LFSResult struct {
|
||||
Name string
|
||||
SHA string
|
||||
Summary string
|
||||
When time.Time
|
||||
ParentHashes []git.ObjectID
|
||||
BranchName string
|
||||
FullCommitName string
|
||||
}
|
||||
|
||||
type lfsResultSlice []*LFSResult
|
||||
|
||||
func (a lfsResultSlice) Len() int { return len(a) }
|
||||
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
|
||||
|
||||
// FindLFSFile finds commits that contain a provided pointer file hash
|
||||
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
|
||||
resultsMap := map[string]*LFSResult{}
|
||||
|
@ -51,7 +32,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to get GoGit CommitsIter. Error: %w", err)
|
||||
return nil, lfsError("failed to get GoGit CommitsIter", err)
|
||||
}
|
||||
|
||||
err = commitsIter.ForEach(func(gitCommit *object.Commit) error {
|
||||
|
@ -85,7 +66,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
return nil
|
||||
})
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, fmt.Errorf("Failure in CommitIter.ForEach: %w", err)
|
||||
return nil, lfsError("failure in CommitIter.ForEach", err)
|
||||
}
|
||||
|
||||
for _, result := range resultsMap {
|
||||
|
@ -156,7 +137,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
select {
|
||||
case err, has := <-errChan:
|
||||
if has {
|
||||
return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
|
||||
return nil, lfsError("unable to obtain name for LFS files", err)
|
||||
}
|
||||
default:
|
||||
}
|
|
@ -8,33 +8,14 @@ package pipeline
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
)
|
||||
|
||||
// LFSResult represents commits found using a provided pointer file hash
|
||||
type LFSResult struct {
|
||||
Name string
|
||||
SHA string
|
||||
Summary string
|
||||
When time.Time
|
||||
ParentIDs []git.ObjectID
|
||||
BranchName string
|
||||
FullCommitName string
|
||||
}
|
||||
|
||||
type lfsResultSlice []*LFSResult
|
||||
|
||||
func (a lfsResultSlice) Len() int { return len(a) }
|
||||
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
|
||||
|
||||
// FindLFSFile finds commits that contain a provided pointer file hash
|
||||
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
|
||||
resultsMap := map[string]*LFSResult{}
|
||||
|
@ -137,11 +118,11 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
n += int64(count)
|
||||
if bytes.Equal(binObjectID, objectID.RawValue()) {
|
||||
result := LFSResult{
|
||||
Name: curPath + string(fname),
|
||||
SHA: curCommit.ID.String(),
|
||||
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
|
||||
When: curCommit.Author.When,
|
||||
ParentIDs: curCommit.Parents,
|
||||
Name: curPath + string(fname),
|
||||
SHA: curCommit.ID.String(),
|
||||
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
|
||||
When: curCommit.Author.When,
|
||||
ParentHashes: curCommit.Parents,
|
||||
}
|
||||
resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result
|
||||
} else if string(mode) == git.EntryModeTree.String() {
|
||||
|
@ -183,7 +164,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
|
||||
for _, result := range resultsMap {
|
||||
hasParent := false
|
||||
for _, parentID := range result.ParentIDs {
|
||||
for _, parentID := range result.ParentHashes {
|
||||
if _, hasParent = resultsMap[parentID.String()+":"+result.Name]; hasParent {
|
||||
break
|
||||
}
|
||||
|
@ -240,7 +221,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
select {
|
||||
case err, has := <-errChan:
|
||||
if has {
|
||||
return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
|
||||
return nil, lfsError("unable to obtain name for LFS files", err)
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"esbuild-loader": "4.1.0",
|
||||
"escape-goat": "4.0.0",
|
||||
"fast-glob": "3.3.2",
|
||||
"htmx.org": "1.9.11",
|
||||
"htmx.org": "1.9.12",
|
||||
"idiomorph": "0.3.0",
|
||||
"jquery": "3.7.1",
|
||||
"katex": "0.16.10",
|
||||
|
@ -6728,9 +6728,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/htmx.org": {
|
||||
"version": "1.9.11",
|
||||
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.11.tgz",
|
||||
"integrity": "sha512-WlVuICn8dfNOOgYmdYzYG8zSnP3++AdHkMHooQAzGZObWpVXYathpz/I37ycF4zikR6YduzfCvEcxk20JkIUsw=="
|
||||
"version": "1.9.12",
|
||||
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.12.tgz",
|
||||
"integrity": "sha512-VZAohXyF7xPGS52IM8d1T1283y+X4D+Owf3qY1NZ9RuBypyu9l8cGsxUMAG5fEAb/DhT7rDoJ9Hpu5/HxFD3cw=="
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "5.0.0",
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"esbuild-loader": "4.1.0",
|
||||
"escape-goat": "4.0.0",
|
||||
"fast-glob": "3.3.2",
|
||||
"htmx.org": "1.9.11",
|
||||
"htmx.org": "1.9.12",
|
||||
"idiomorph": "0.3.0",
|
||||
"jquery": "3.7.1",
|
||||
"katex": "0.16.10",
|
||||
|
|
|
@ -67,6 +67,9 @@ type ViewResponse struct {
|
|||
CanRerun bool `json:"canRerun"`
|
||||
CanDeleteArtifact bool `json:"canDeleteArtifact"`
|
||||
Done bool `json:"done"`
|
||||
WorkflowID string `json:"workflowID"`
|
||||
WorkflowLink string `json:"workflowLink"`
|
||||
IsSchedule bool `json:"isSchedule"`
|
||||
Jobs []*ViewJob `json:"jobs"`
|
||||
Commit ViewCommit `json:"commit"`
|
||||
} `json:"run"`
|
||||
|
@ -90,12 +93,10 @@ type ViewJob struct {
|
|||
}
|
||||
|
||||
type ViewCommit struct {
|
||||
LocaleCommit string `json:"localeCommit"`
|
||||
LocalePushedBy string `json:"localePushedBy"`
|
||||
ShortSha string `json:"shortSHA"`
|
||||
Link string `json:"link"`
|
||||
Pusher ViewUser `json:"pusher"`
|
||||
Branch ViewBranch `json:"branch"`
|
||||
ShortSha string `json:"shortSHA"`
|
||||
Link string `json:"link"`
|
||||
Pusher ViewUser `json:"pusher"`
|
||||
Branch ViewBranch `json:"branch"`
|
||||
}
|
||||
|
||||
type ViewUser struct {
|
||||
|
@ -151,6 +152,9 @@ func ViewPost(ctx *context_module.Context) {
|
|||
resp.State.Run.CanRerun = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
|
||||
resp.State.Run.CanDeleteArtifact = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
|
||||
resp.State.Run.Done = run.Status.IsDone()
|
||||
resp.State.Run.WorkflowID = run.WorkflowID
|
||||
resp.State.Run.WorkflowLink = run.WorkflowLink()
|
||||
resp.State.Run.IsSchedule = run.IsSchedule()
|
||||
resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json
|
||||
resp.State.Run.Status = run.Status.String()
|
||||
for _, v := range jobs {
|
||||
|
@ -172,12 +176,10 @@ func ViewPost(ctx *context_module.Context) {
|
|||
Link: run.RefLink(),
|
||||
}
|
||||
resp.State.Run.Commit = ViewCommit{
|
||||
LocaleCommit: ctx.Locale.TrString("actions.runs.commit"),
|
||||
LocalePushedBy: ctx.Locale.TrString("actions.runs.pushed_by"),
|
||||
ShortSha: base.ShortSha(run.CommitSHA),
|
||||
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),
|
||||
Pusher: pusher,
|
||||
Branch: branch,
|
||||
ShortSha: base.ShortSha(run.CommitSHA),
|
||||
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),
|
||||
Pusher: pusher,
|
||||
Branch: branch,
|
||||
}
|
||||
|
||||
var task *actions_model.ActionTask
|
||||
|
|
|
@ -3149,13 +3149,10 @@ func UpdateCommentContent(ctx *context.Context) {
|
|||
}
|
||||
|
||||
oldContent := comment.Content
|
||||
comment.Content = ctx.FormString("content")
|
||||
if len(comment.Content) == 0 {
|
||||
ctx.JSON(http.StatusOK, map[string]any{
|
||||
"content": "",
|
||||
})
|
||||
return
|
||||
}
|
||||
newContent := ctx.FormString("content")
|
||||
|
||||
// allow to save empty content
|
||||
comment.Content = newContent
|
||||
if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil {
|
||||
if errors.Is(err, user_model.ErrBlockedUser) {
|
||||
ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_user"))
|
||||
|
@ -3178,21 +3175,27 @@ func UpdateCommentContent(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
content, err := markdown.RenderString(&markup.RenderContext{
|
||||
Links: markup.Links{
|
||||
Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
|
||||
},
|
||||
Metas: ctx.Repo.Repository.ComposeMetas(ctx),
|
||||
GitRepo: ctx.Repo.GitRepo,
|
||||
Ctx: ctx,
|
||||
}, comment.Content)
|
||||
if err != nil {
|
||||
ctx.ServerError("RenderString", err)
|
||||
return
|
||||
var renderedContent template.HTML
|
||||
if comment.Content != "" {
|
||||
renderedContent, err = markdown.RenderString(&markup.RenderContext{
|
||||
Links: markup.Links{
|
||||
Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
|
||||
},
|
||||
Metas: ctx.Repo.Repository.ComposeMetas(ctx),
|
||||
GitRepo: ctx.Repo.GitRepo,
|
||||
Ctx: ctx,
|
||||
}, comment.Content)
|
||||
if err != nil {
|
||||
ctx.ServerError("RenderString", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
contentEmpty := fmt.Sprintf(`<span class="no-content">%s</span>`, ctx.Tr("repo.issues.no_content"))
|
||||
renderedContent = template.HTML(contentEmpty)
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]any{
|
||||
"content": content,
|
||||
"content": renderedContent,
|
||||
"attachments": attachmentsHTML(ctx, comment.Attachments, comment.Content),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
{{if .Title}}{{.Title}}{{else}}{{ctx.Locale.Tr "actions.runs.empty_commit_message"}}{{end}}
|
||||
</a>
|
||||
<div class="flex-item-body">
|
||||
<b>{{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}</b>:
|
||||
<span><b>{{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}</b>:</span>
|
||||
{{- if .ScheduleID -}}
|
||||
{{ctx.Locale.Tr "actions.runs.scheduled"}}
|
||||
{{- else -}}
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
data-locale-cancel="{{ctx.Locale.Tr "cancel"}}"
|
||||
data-locale-rerun="{{ctx.Locale.Tr "rerun"}}"
|
||||
data-locale-rerun-all="{{ctx.Locale.Tr "rerun_all"}}"
|
||||
data-locale-runs-scheduled="{{ctx.Locale.Tr "actions.runs.scheduled"}}"
|
||||
data-locale-runs-commit="{{ctx.Locale.Tr "actions.runs.commit"}}"
|
||||
data-locale-runs-pushed-by="{{ctx.Locale.Tr "actions.runs.pushed_by"}}"
|
||||
data-locale-status-unknown="{{ctx.Locale.Tr "actions.status.unknown"}}"
|
||||
data-locale-status-waiting="{{ctx.Locale.Tr "actions.status.waiting"}}"
|
||||
data-locale-status-running="{{ctx.Locale.Tr "actions.status.running"}}"
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -46,22 +48,25 @@ func TestPullCompare(t *testing.T) {
|
|||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther)
|
||||
testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
|
||||
resp = testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title")
|
||||
testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title")
|
||||
|
||||
// the max value on issue_index.yml for repo_id=1 is 5
|
||||
req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files")
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
|
||||
issueIndex := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueIndex{GroupID: repo1.ID}, unittest.OrderBy("group_id ASC"))
|
||||
prFilesURL := fmt.Sprintf("/user2/repo1/pulls/%d/files", issueIndex.MaxIndex)
|
||||
req = NewRequest(t, "GET", prFilesURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length()
|
||||
assert.Greater(t, editButtonCount, 0, "Expected to find a button to edit a file in the PR diff view but there were none")
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repoForked := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"})
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
// delete the head repository and revisit the PR diff view
|
||||
err := repo_service.DeleteRepositoryDirectly(db.DefaultContext, user2, repoForked.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files")
|
||||
req = NewRequest(t, "GET", prFilesURL)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
doc = NewHTMLParser(t, resp.Body)
|
||||
editButtonCount = doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length()
|
||||
|
|
|
@ -44,6 +44,9 @@ const sfc = {
|
|||
canApprove: false,
|
||||
canRerun: false,
|
||||
done: false,
|
||||
workflowID: '',
|
||||
workflowLink: '',
|
||||
isSchedule: false,
|
||||
jobs: [
|
||||
// {
|
||||
// id: 0,
|
||||
|
@ -338,10 +341,13 @@ export function initRepositoryActionView() {
|
|||
approve: el.getAttribute('data-locale-approve'),
|
||||
cancel: el.getAttribute('data-locale-cancel'),
|
||||
rerun: el.getAttribute('data-locale-rerun'),
|
||||
rerun_all: el.getAttribute('data-locale-rerun-all'),
|
||||
scheduled: el.getAttribute('data-locale-runs-scheduled'),
|
||||
commit: el.getAttribute('data-locale-runs-commit'),
|
||||
pushedBy: el.getAttribute('data-locale-runs-pushed-by'),
|
||||
artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
|
||||
areYouSure: el.getAttribute('data-locale-are-you-sure'),
|
||||
confirmDeleteArtifact: el.getAttribute('data-locale-confirm-delete-artifact'),
|
||||
rerun_all: el.getAttribute('data-locale-rerun-all'),
|
||||
showTimeStamps: el.getAttribute('data-locale-show-timestamps'),
|
||||
showLogSeconds: el.getAttribute('data-locale-show-log-seconds'),
|
||||
showFullScreen: el.getAttribute('data-locale-show-full-screen'),
|
||||
|
@ -382,10 +388,16 @@ export function initRepositoryActionView() {
|
|||
</button>
|
||||
</div>
|
||||
<div class="action-commit-summary">
|
||||
{{ run.commit.localeCommit }}
|
||||
<a class="muted" :href="run.commit.link">{{ run.commit.shortSHA }}</a>
|
||||
{{ run.commit.localePushedBy }}
|
||||
<a class="muted" :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a>
|
||||
<span><a class="muted" :href="run.workflowLink"><b>{{ run.workflowID }}</b></a>:</span>
|
||||
<template v-if="run.isSchedule">
|
||||
{{ locale.scheduled }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ locale.commit }}
|
||||
<a class="muted" :href="run.commit.link">{{ run.commit.shortSHA }}</a>
|
||||
{{ locale.pushedBy }}
|
||||
<a class="muted" :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a>
|
||||
</template>
|
||||
<span class="ui label tw-max-w-full" v-if="run.commit.shortSHA">
|
||||
<a class="gt-ellipsis" :href="run.commit.branch.link">{{ run.commit.branch.name }}</a>
|
||||
</span>
|
||||
|
|
Loading…
Reference in New Issue