Compare commits

..

No commits in common. "86d65ba0bebd48470a7fa1240f8566dfdd4d6242" and "d48ff06b069dc4c50cb344838ec4f9d41f2302f6" have entirely different histories.

43 changed files with 102 additions and 621 deletions

View file

@ -47,6 +47,7 @@ GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasour
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.18.1 # renovate: datasource=go
RENOVATE_NPM_PACKAGE ?= renovate@40.57.1 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate RENOVATE_NPM_PACKAGE ?= renovate@40.57.1 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
# https://github.com/disposable-email-domains/disposable-email-domains/commits/main/ # https://github.com/disposable-email-domains/disposable-email-domains/commits/main/
@ -221,6 +222,7 @@ help:
@echo " - lint-go lint go files" @echo " - lint-go lint go files"
@echo " - lint-go-fix lint go files and fix issues" @echo " - lint-go-fix lint go files and fix issues"
@echo " - lint-go-vet lint go files with vet" @echo " - lint-go-vet lint go files with vet"
@echo " - lint-go-gopls lint go files with gopls"
@echo " - lint-js lint js files" @echo " - lint-js lint js files"
@echo " - lint-js-fix lint js files and fix issues" @echo " - lint-js-fix lint js files and fix issues"
@echo " - lint-css lint css files" @echo " - lint-css lint css files"
@ -485,6 +487,11 @@ lint-go-vet:
@echo "Running go vet..." @echo "Running go vet..."
@$(GO) vet ./... @$(GO) vet ./...
.PHONY: lint-go-gopls
lint-go-gopls:
@echo "Running gopls check..."
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA)
.PHONY: lint-editorconfig .PHONY: lint-editorconfig
lint-editorconfig: lint-editorconfig:
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows $(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows
@ -925,6 +932,7 @@ deps-tools:
$(GO) install $(GO_LICENSES_PACKAGE) $(GO) install $(GO_LICENSES_PACKAGE)
$(GO) install $(GOVULNCHECK_PACKAGE) $(GO) install $(GOVULNCHECK_PACKAGE)
$(GO) install $(GOMOCK_PACKAGE) $(GO) install $(GOMOCK_PACKAGE)
$(GO) install $(GOPLS_PACKAGE)
node_modules: package-lock.json node_modules: package-lock.json
npm install --no-save npm install --no-save

View file

@ -113,43 +113,3 @@
review_id: 22 review_id: 22
assignee_id: 5 assignee_id: 5
created_unix: 946684817 created_unix: 946684817
-
id: 13
type: 29 # push
poster_id: 2
issue_id: 19 # in repo_id 58
content: '{"is_force_push":false,"commit_ids":["4ca8bcaf27e28504df7bf996819665986b01c847","96cef4a7b72b3c208340ae6f0cf55a93e9077c93","c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2"]}'
created_unix: 1688672373
-
id: 14
type: 29 # push
poster_id: 2
issue_id: 19 # in repo_id 58
content: '{"is_force_push":false,"commit_ids":["23576dd018294e476c06e569b6b0f170d0558705"]}'
created_unix: 1688672374
-
id: 15
type: 29 # push
poster_id: 2
issue_id: 19 # in repo_id 58
content: '{"is_force_push":false,"commit_ids":["3e64625bd6eb5bcba69ac97de6c8f507402df861", "c704db5794097441aa2d9dd834d5b7e2f8f08108"]}'
created_unix: 1688672375
-
id: 16
type: 29 # push
poster_id: 2
issue_id: 19 # in repo_id 58
content: '{"is_force_push":false,"commit_ids":["811d46c7e518f4f180afb862c0db5cb8c80529ce", "747ddb3506a4fa04a7747808eb56ae16f9e933dc", "837d5c8125633d7d258f93b998e867eab0145520", "1978192d98bb1b65e11c2cf37da854fbf94bffd6"]}'
created_unix: 1688672376
-
id: 17
type: 29 # push
poster_id: 2
issue_id: 19 # in repo_id 58
content: '{"is_force_push":true,"commit_ids":["1978192d98bb1b65e11c2cf37da854fbf94bffd6", "9b93963cf6de4dc33f915bb67f192d099c301f43"]}'
created_unix: 1749734240

View file

@ -1 +0,0 @@
[] # empty

View file

@ -66,8 +66,6 @@ func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {
sess.Asc("issue.created_unix").Asc("issue.id") sess.Asc("issue.created_unix").Asc("issue.id")
case "recentupdate": case "recentupdate":
sess.Desc("issue.updated_unix").Desc("issue.created_unix").Desc("issue.id") sess.Desc("issue.updated_unix").Desc("issue.created_unix").Desc("issue.id")
case "recentclose":
sess.Desc("issue.closed_unix").Desc("issue.created_unix").Desc("issue.id")
case "leastupdate": case "leastupdate":
sess.Asc("issue.updated_unix").Asc("issue.created_unix").Asc("issue.id") sess.Asc("issue.updated_unix").Asc("issue.created_unix").Asc("issue.id")
case "mostcomment": case "mostcomment":

View file

@ -152,8 +152,7 @@ func PullRequests(ctx context.Context, baseRepoID int64, opts *PullRequestsOptio
applySorts(findSession, opts.SortType, 0) applySorts(findSession, opts.SortType, 0)
findSession = db.SetSessionPagination(findSession, opts) findSession = db.SetSessionPagination(findSession, opts)
prs := make([]*PullRequest, 0, opts.PageSize) prs := make([]*PullRequest, 0, opts.PageSize)
found := findSession.Find(&prs) return prs, maxResults, findSession.Find(&prs)
return prs, maxResults, found
} }
// PullRequestList defines a list of pull requests // PullRequestList defines a list of pull requests

View file

@ -79,47 +79,6 @@ func TestPullRequestsNewest(t *testing.T) {
} }
} }
func TestPullRequests_Closed_RecentSortType(t *testing.T) {
// Issue ID | Closed At. | Updated At
// 2 | 1707270001 | 1707270001
// 3 | 1707271000 | 1707279999
// 11 | 1707279999 | 1707275555
tests := []struct {
sortType string
expectedIssueIDOrder []int64
}{
{"recentupdate", []int64{3, 11, 2}},
{"recentclose", []int64{11, 3, 2}},
}
require.NoError(t, unittest.PrepareTestDatabase())
_, err := db.Exec(db.DefaultContext, "UPDATE issue SET closed_unix = 1707270001, updated_unix = 1707270001, is_closed = true WHERE id = 2")
require.NoError(t, err)
_, err = db.Exec(db.DefaultContext, "UPDATE issue SET closed_unix = 1707271000, updated_unix = 1707279999, is_closed = true WHERE id = 3")
require.NoError(t, err)
_, err = db.Exec(db.DefaultContext, "UPDATE issue SET closed_unix = 1707279999, updated_unix = 1707275555, is_closed = true WHERE id = 11")
require.NoError(t, err)
for _, test := range tests {
t.Run(test.sortType, func(t *testing.T) {
prs, _, err := issues_model.PullRequests(db.DefaultContext, 1, &issues_model.PullRequestsOptions{
ListOptions: db.ListOptions{
Page: 1,
},
State: "closed",
SortType: test.sortType,
})
require.NoError(t, err)
if assert.Len(t, prs, len(test.expectedIssueIDOrder)) {
for i := range test.expectedIssueIDOrder {
assert.Equal(t, test.expectedIssueIDOrder[i], prs[i].IssueID)
}
}
})
}
}
func TestLoadRequestedReviewers(t *testing.T) { func TestLoadRequestedReviewers(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase()) require.NoError(t, unittest.PrepareTestDatabase())

View file

@ -10,7 +10,6 @@ import (
"forgejo.org/models/db" "forgejo.org/models/db"
repo_model "forgejo.org/models/repo" repo_model "forgejo.org/models/repo"
user_model "forgejo.org/models/user" user_model "forgejo.org/models/user"
"forgejo.org/modules/log"
"forgejo.org/modules/timeutil" "forgejo.org/modules/timeutil"
) )
@ -59,15 +58,13 @@ func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64,
return ErrAlreadyScheduledToAutoMerge{PullID: pullID} return ErrAlreadyScheduledToAutoMerge{PullID: pullID}
} }
scheduledPRM, err := db.GetEngine(ctx).Insert(&AutoMerge{ _, err := db.GetEngine(ctx).Insert(&AutoMerge{
DoerID: doer.ID, DoerID: doer.ID,
PullID: pullID, PullID: pullID,
MergeStyle: style, MergeStyle: style,
Message: message, Message: message,
DeleteBranchAfterMerge: deleteBranch, DeleteBranchAfterMerge: deleteBranch,
}) })
log.Trace("ScheduleAutoMerge %+v for PR %d", scheduledPRM, pullID)
return err return err
} }
@ -84,8 +81,6 @@ func GetScheduledMergeByPullID(ctx context.Context, pullID int64) (bool, *AutoMe
return false, nil, err return false, nil, err
} }
log.Trace("GetScheduledMergeByPullID found %+v for PR %d", scheduledPRM, pullID)
scheduledPRM.Doer = doer scheduledPRM.Doer = doer
return true, scheduledPRM, nil return true, scheduledPRM, nil
} }
@ -99,8 +94,6 @@ func DeleteScheduledAutoMerge(ctx context.Context, pullID int64) error {
return db.ErrNotExist{Resource: "auto_merge", ID: pullID} return db.ErrNotExist{Resource: "auto_merge", ID: pullID}
} }
log.Trace("DeleteScheduledAutoMerge %+v for PR %d", scheduledPRM, pullID)
_, err = db.GetEngine(ctx).ID(scheduledPRM.ID).Delete(&AutoMerge{}) _, err = db.GetEngine(ctx).ID(scheduledPRM.ID).Delete(&AutoMerge{})
return err return err
} }

View file

@ -89,8 +89,6 @@
"mail.actions.run_info_previous_status": "Previous Run's Status: %[1]s", "mail.actions.run_info_previous_status": "Previous Run's Status: %[1]s",
"mail.actions.run_info_ref": "Branch: %[1]s (%[2]s)", "mail.actions.run_info_ref": "Branch: %[1]s (%[2]s)",
"mail.actions.run_info_trigger": "Triggered because: %[1]s by: %[2]s", "mail.actions.run_info_trigger": "Triggered because: %[1]s by: %[2]s",
"repo.diff.commit.next-short": "Next",
"repo.diff.commit.previous-short": "Prev",
"discussion.locked": "This discussion has been locked. Commenting is limited to contributors.", "discussion.locked": "This discussion has been locked. Commenting is limited to contributors.",
"editor.textarea.tab_hint": "Line already indented. Press <kbd>Tab</kbd> again or <kbd>Escape</kbd> to leave the editor.", "editor.textarea.tab_hint": "Line already indented. Press <kbd>Tab</kbd> again or <kbd>Escape</kbd> to leave the editor.",
"editor.textarea.shift_tab_hint": "No indentation on this line. Press <kbd>Shift</kbd> + <kbd>Tab</kbd> again or <kbd>Escape</kbd> to leave the editor.", "editor.textarea.shift_tab_hint": "No indentation on this line. Press <kbd>Shift</kbd> + <kbd>Tab</kbd> again or <kbd>Escape</kbd> to leave the editor.",

8
package-lock.json generated
View file

@ -16,7 +16,7 @@
"@primer/octicons": "19.14.0", "@primer/octicons": "19.14.0",
"ansi_up": "6.0.5", "ansi_up": "6.0.5",
"asciinema-player": "3.8.2", "asciinema-player": "3.8.2",
"chart.js": "4.5.0", "chart.js": "4.4.9",
"chartjs-adapter-dayjs-4": "1.0.4", "chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0", "chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.7", "clippie": "4.1.7",
@ -5373,9 +5373,9 @@
} }
}, },
"node_modules/chart.js": { "node_modules/chart.js": {
"version": "4.5.0", "version": "4.4.9",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.9.tgz",
"integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", "integrity": "sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@kurkle/color": "^0.3.0" "@kurkle/color": "^0.3.0"

View file

@ -15,7 +15,7 @@
"@primer/octicons": "19.14.0", "@primer/octicons": "19.14.0",
"ansi_up": "6.0.5", "ansi_up": "6.0.5",
"asciinema-player": "3.8.2", "asciinema-player": "3.8.2",
"chart.js": "4.5.0", "chart.js": "4.4.9",
"chartjs-adapter-dayjs-4": "1.0.4", "chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0", "chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.7", "clippie": "4.1.7",

View file

@ -71,7 +71,7 @@ func ListPullRequests(ctx *context.APIContext) {
// in: query // in: query
// description: Type of sort // description: Type of sort
// type: string // type: string
// enum: [oldest, recentupdate, recentclose, leastupdate, mostcomment, leastcomment, priority] // enum: [oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority]
// - name: milestone // - name: milestone
// in: query // in: query
// description: ID of the milestone // description: ID of the milestone

View file

@ -10,16 +10,13 @@ import (
"errors" "errors"
"fmt" "fmt"
"html" "html"
"html/template"
"net/http" "net/http"
"net/url" "net/url"
"path"
"strconv" "strconv"
"strings" "strings"
"forgejo.org/models" "forgejo.org/models"
activities_model "forgejo.org/models/activities" activities_model "forgejo.org/models/activities"
asymkey_model "forgejo.org/models/asymkey"
"forgejo.org/models/db" "forgejo.org/models/db"
git_model "forgejo.org/models/git" git_model "forgejo.org/models/git"
issues_model "forgejo.org/models/issues" issues_model "forgejo.org/models/issues"
@ -31,13 +28,11 @@ import (
"forgejo.org/models/unit" "forgejo.org/models/unit"
user_model "forgejo.org/models/user" user_model "forgejo.org/models/user"
"forgejo.org/modules/base" "forgejo.org/modules/base"
"forgejo.org/modules/charset"
"forgejo.org/modules/emoji" "forgejo.org/modules/emoji"
"forgejo.org/modules/git" "forgejo.org/modules/git"
"forgejo.org/modules/gitrepo" "forgejo.org/modules/gitrepo"
issue_template "forgejo.org/modules/issue/template" issue_template "forgejo.org/modules/issue/template"
"forgejo.org/modules/log" "forgejo.org/modules/log"
"forgejo.org/modules/markup"
"forgejo.org/modules/optional" "forgejo.org/modules/optional"
"forgejo.org/modules/setting" "forgejo.org/modules/setting"
"forgejo.org/modules/structs" "forgejo.org/modules/structs"
@ -503,7 +498,6 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
ctx.Data["IsPullRequestBroken"] = true ctx.Data["IsPullRequestBroken"] = true
ctx.Data["BaseTarget"] = pull.BaseBranch ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0 ctx.Data["NumCommits"] = 0
ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0 ctx.Data["NumFiles"] = 0
return nil return nil
} }
@ -514,12 +508,6 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
ctx.Data["NumCommits"] = len(compareInfo.Commits) ctx.Data["NumCommits"] = len(compareInfo.Commits)
ctx.Data["NumFiles"] = compareInfo.NumFiles ctx.Data["NumFiles"] = compareInfo.NumFiles
commitIDs := map[string]bool{}
for _, commit := range compareInfo.Commits {
commitIDs[commit.ID.String()] = true
}
ctx.Data["CommitIDs"] = commitIDs
if len(compareInfo.Commits) != 0 { if len(compareInfo.Commits) != 0 {
sha := compareInfo.Commits[0].ID.String() sha := compareInfo.Commits[0].ID.String()
commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll) commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll)
@ -603,7 +591,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["IsPullRequestBroken"] = true ctx.Data["IsPullRequestBroken"] = true
ctx.Data["BaseTarget"] = pull.BaseBranch ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0 ctx.Data["NumCommits"] = 0
ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0 ctx.Data["NumFiles"] = 0
return nil return nil
} }
@ -614,13 +601,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["NumCommits"] = len(compareInfo.Commits) ctx.Data["NumCommits"] = len(compareInfo.Commits)
ctx.Data["NumFiles"] = compareInfo.NumFiles ctx.Data["NumFiles"] = compareInfo.NumFiles
commitIDs := map[string]bool{}
for _, commit := range compareInfo.Commits {
commitIDs[commit.ID.String()] = true
}
ctx.Data["CommitIDs"] = commitIDs
return compareInfo return compareInfo
} }
@ -679,7 +659,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
} }
ctx.Data["BaseTarget"] = pull.BaseBranch ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0 ctx.Data["NumCommits"] = 0
ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0 ctx.Data["NumFiles"] = 0
return nil return nil
} }
@ -757,7 +736,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["IsPullRequestBroken"] = true ctx.Data["IsPullRequestBroken"] = true
ctx.Data["BaseTarget"] = pull.BaseBranch ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0 ctx.Data["NumCommits"] = 0
ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0 ctx.Data["NumFiles"] = 0
return nil return nil
} }
@ -782,13 +760,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["NumCommits"] = len(compareInfo.Commits) ctx.Data["NumCommits"] = len(compareInfo.Commits)
ctx.Data["NumFiles"] = compareInfo.NumFiles ctx.Data["NumFiles"] = compareInfo.NumFiles
commitIDs := map[string]bool{}
for _, commit := range compareInfo.Commits {
commitIDs[commit.ID.String()] = true
}
ctx.Data["CommitIDs"] = commitIDs
return compareInfo return compareInfo
} }
@ -948,78 +919,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
ctx.Data["IsShowingOnlySingleCommit"] = willShowSpecifiedCommit ctx.Data["IsShowingOnlySingleCommit"] = willShowSpecifiedCommit
if willShowSpecifiedCommit { if willShowSpecifiedCommit || willShowSpecifiedCommitRange {
commitID := specifiedEndCommit
ctx.Data["CommitID"] = commitID
var prevCommit, curCommit, nextCommit *git.Commit
// Iterate in reverse to properly map "previous" and "next" buttons
for i := len(prInfo.Commits) - 1; i >= 0; i-- {
commit := prInfo.Commits[i]
if curCommit != nil {
nextCommit = commit
break
}
if commit.ID.String() == commitID {
curCommit = commit
} else {
prevCommit = commit
}
}
if curCommit == nil {
ctx.ServerError("Repo.GitRepo.viewPullFiles", git.ErrNotExist{ID: commitID})
return
}
ctx.Data["Commit"] = curCommit
if prevCommit != nil {
ctx.Data["PrevCommitLink"] = path.Join(ctx.Repo.RepoLink, "pulls", strconv.FormatInt(issue.Index, 10), "commits", prevCommit.ID.String())
}
if nextCommit != nil {
ctx.Data["NextCommitLink"] = path.Join(ctx.Repo.RepoLink, "pulls", strconv.FormatInt(issue.Index, 10), "commits", nextCommit.ID.String())
}
statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll)
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
}
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses
verification := asymkey_model.ParseCommitWithSignature(ctx, curCommit)
ctx.Data["Verification"] = verification
ctx.Data["Author"] = user_model.ValidateCommitWithEmail(ctx, curCommit)
note := &git.Note{}
err = git.GetNote(ctx, ctx.Repo.GitRepo, specifiedEndCommit, note)
if err == nil {
ctx.Data["NoteCommit"] = note.Commit
ctx.Data["NoteAuthor"] = user_model.ValidateCommitWithEmail(ctx, note.Commit)
ctx.Data["NoteRendered"], err = markup.RenderCommitMessage(&markup.RenderContext{
Links: markup.Links{
Base: ctx.Repo.RepoLink,
BranchPath: path.Join("commit", util.PathEscapeSegments(commitID)),
},
Metas: ctx.Repo.Repository.ComposeMetas(ctx),
GitRepo: ctx.Repo.GitRepo,
Ctx: ctx,
}, template.HTMLEscapeString(string(charset.ToUTF8WithFallback(note.Message, charset.ConvertOpts{}))))
if err != nil {
ctx.ServerError("RenderCommitMessage", err)
return
}
}
endCommitID = commitID
startCommitID = prInfo.MergeBase
ctx.Data["IsShowingAllCommits"] = false
} else if willShowSpecifiedCommitRange {
if len(specifiedEndCommit) > 0 { if len(specifiedEndCommit) > 0 {
endCommitID = specifiedEndCommit endCommitID = specifiedEndCommit
} else { } else {
@ -1030,7 +930,6 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
} else { } else {
startCommitID = prInfo.MergeBase startCommitID = prInfo.MergeBase
} }
ctx.Data["IsShowingAllCommits"] = false ctx.Data["IsShowingAllCommits"] = false
} else { } else {
endCommitID = headCommitID endCommitID = headCommitID
@ -1038,10 +937,10 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
ctx.Data["IsShowingAllCommits"] = true ctx.Data["IsShowingAllCommits"] = true
} }
ctx.Data["AfterCommitID"] = endCommitID
ctx.Data["BeforeCommitID"] = startCommitID
ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name
ctx.Data["AfterCommitID"] = endCommitID
ctx.Data["BeforeCommitID"] = startCommitID
fileOnly := ctx.FormBool("file-only") fileOnly := ctx.FormBool("file-only")

View file

@ -1511,10 +1511,7 @@ func registerRoutes(m *web.Route) {
m.Group("/commits", func() { m.Group("/commits", func() {
m.Get("", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits) m.Get("", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits)
m.Get("/list", context.RepoRef(), repo.GetPullCommits) m.Get("/list", context.RepoRef(), repo.GetPullCommits)
m.Group("/{sha:[a-f0-9]{4,40}}", func() { m.Get("/{sha:[a-f0-9]{4,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
m.Post("/reviews/submit", context.RepoMustNotBeArchived(), web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview)
})
}) })
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.MergePullRequest) m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.MergePullRequest)
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest) m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)

View file

@ -107,7 +107,6 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
return return
} }
if !exists { if !exists {
log.Trace("GetScheduledMergeByPullID found nothing for PR %d", pullID)
return return
} }
@ -205,10 +204,6 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
return return
} }
if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) {
log.Error("DeleteScheduledAutoMerge[%d]: %v", pr.ID, err)
}
if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil { if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil {
log.Error("pull_service.Merge: %v", err) log.Error("pull_service.Merge: %v", err)
// FIXME: if merge failed, we should display some error message to the pull request page. // FIXME: if merge failed, we should display some error message to the pull request page.

View file

@ -28,7 +28,6 @@ import (
"forgejo.org/modules/timeutil" "forgejo.org/modules/timeutil"
asymkey_service "forgejo.org/services/asymkey" asymkey_service "forgejo.org/services/asymkey"
notify_service "forgejo.org/services/notify" notify_service "forgejo.org/services/notify"
shared_automerge "forgejo.org/services/shared/automerge"
) )
// prPatchCheckerQueue represents a queue to handle update pull request tests // prPatchCheckerQueue represents a queue to handle update pull request tests
@ -171,7 +170,7 @@ func isSignedIfRequired(ctx context.Context, pr *issues_model.PullRequest, doer
// checkAndUpdateStatus checks if pull request is possible to leaving checking status, // checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable. // and set to be either conflict or mergeable.
func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) bool { func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) {
// If status has not been changed to conflict by testPatch then we are mergeable // If status has not been changed to conflict by testPatch then we are mergeable
if pr.Status == issues_model.PullRequestStatusChecking { if pr.Status == issues_model.PullRequestStatusChecking {
pr.Status = issues_model.PullRequestStatusMergeable pr.Status = issues_model.PullRequestStatusMergeable
@ -185,15 +184,12 @@ func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) boo
if has { if has {
log.Trace("Not updating status for %-v as it is due to be rechecked", pr) log.Trace("Not updating status for %-v as it is due to be rechecked", pr)
return false return
} }
if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil { if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil {
log.Error("Update[%-v]: %v", pr, err) log.Error("Update[%-v]: %v", pr, err)
return false
} }
return true
} }
// getMergeCommit checks if a pull request has been merged // getMergeCommit checks if a pull request has been merged
@ -343,22 +339,15 @@ func handler(items ...string) []string {
} }
func testPR(id int64) { func testPR(id int64) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("Test PR[%d] from patch checking queue", id))
defer finished()
if pr, updated := testPRProtected(ctx, id); pr != nil && updated {
shared_automerge.AddToQueueIfMergeable(ctx, pr)
}
}
func testPRProtected(ctx context.Context, id int64) (*issues_model.PullRequest, bool) {
pullWorkingPool.CheckIn(fmt.Sprint(id)) pullWorkingPool.CheckIn(fmt.Sprint(id))
defer pullWorkingPool.CheckOut(fmt.Sprint(id)) defer pullWorkingPool.CheckOut(fmt.Sprint(id))
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("Test PR[%d] from patch checking queue", id))
defer finished()
pr, err := issues_model.GetPullRequestByID(ctx, id) pr, err := issues_model.GetPullRequestByID(ctx, id)
if err != nil { if err != nil {
log.Error("Unable to GetPullRequestByID[%d] for testPR: %v", id, err) log.Error("Unable to GetPullRequestByID[%d] for testPR: %v", id, err)
return nil, false return
} }
log.Trace("Testing %-v", pr) log.Trace("Testing %-v", pr)
@ -368,12 +357,12 @@ func testPRProtected(ctx context.Context, id int64) (*issues_model.PullRequest,
if pr.HasMerged { if pr.HasMerged {
log.Trace("%-v is already merged (status: %s, merge commit: %s)", pr, pr.Status, pr.MergedCommitID) log.Trace("%-v is already merged (status: %s, merge commit: %s)", pr, pr.Status, pr.MergedCommitID)
return nil, false return
} }
if manuallyMerged(ctx, pr) { if manuallyMerged(ctx, pr) {
log.Trace("%-v is manually merged (status: %s, merge commit: %s)", pr, pr.Status, pr.MergedCommitID) log.Trace("%-v is manually merged (status: %s, merge commit: %s)", pr, pr.Status, pr.MergedCommitID)
return nil, false return
} }
if err := TestPatch(pr); err != nil { if err := TestPatch(pr); err != nil {
@ -382,10 +371,9 @@ func testPRProtected(ctx context.Context, id int64) (*issues_model.PullRequest,
if err := pr.UpdateCols(ctx, "status"); err != nil { if err := pr.UpdateCols(ctx, "status"); err != nil {
log.Error("update pr [%-v] status to PullRequestStatusError failed: %v", pr, err) log.Error("update pr [%-v] status to PullRequestStatusError failed: %v", pr, err)
} }
return nil, false return
} }
checkAndUpdateStatus(ctx, pr)
return pr, checkAndUpdateStatus(ctx, pr)
} }
// CheckPRsForBaseBranch check all pulls with baseBrannch // CheckPRsForBaseBranch check all pulls with baseBrannch

View file

@ -21,9 +21,9 @@ import (
var PRAutoMergeQueue *queue.WorkerPoolQueue[string] var PRAutoMergeQueue *queue.WorkerPoolQueue[string]
func addToQueue(pr *issues_model.PullRequest, sha string) { func addToQueue(pr *issues_model.PullRequest, sha string) {
log.Trace("Adding pullID: %d to the automerge queue with sha %s", pr.ID, sha) log.Trace("Adding pullID: %d to the pull requests patch checking queue with sha %s", pr.ID, sha)
if err := PRAutoMergeQueue.Push(fmt.Sprintf("%d_%s", pr.ID, sha)); err != nil { if err := PRAutoMergeQueue.Push(fmt.Sprintf("%d_%s", pr.ID, sha)); err != nil {
log.Error("Error adding pullID: %d to the automerge queue %v", pr.ID, err) log.Error("Error adding pullID: %d to the pull requests patch checking queue %v", pr.ID, err)
} }
} }
@ -43,29 +43,32 @@ func StartPRCheckAndAutoMergeBySHA(ctx context.Context, sha string, repo *repo_m
return nil return nil
} }
// StartPRCheckAndAutoMerge start an automerge check and auto merge task for a pull request
func StartPRCheckAndAutoMerge(ctx context.Context, pull *issues_model.PullRequest) { func StartPRCheckAndAutoMerge(ctx context.Context, pull *issues_model.PullRequest) {
if pull == nil || pull.HasMerged || !pull.CanAutoMerge() { if pull == nil || pull.HasMerged || !pull.CanAutoMerge() {
return return
} }
commitID := pull.HeadCommitID if err := pull.LoadBaseRepo(ctx); err != nil {
if commitID == "" { log.Error("LoadBaseRepo: %v", err)
commitID = getCommitIDFromRefName(ctx, pull) return
} }
if commitID == "" { gitRepo, err := gitrepo.OpenRepository(ctx, pull.BaseRepo)
if err != nil {
log.Error("OpenRepository: %v", err)
return
}
defer gitRepo.Close()
commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
return return
} }
addToQueue(pull, commitID) addToQueue(pull, commitID)
} }
var AddToQueueIfMergeable = func(ctx context.Context, pull *issues_model.PullRequest) {
if pull.Status == issues_model.PullRequestStatusMergeable {
StartPRCheckAndAutoMerge(ctx, pull)
}
}
func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) { func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) {
gitRepo, err := gitrepo.OpenRepository(ctx, repo) gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil { if err != nil {
@ -115,24 +118,3 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.
return pulls, nil return pulls, nil
} }
func getCommitIDFromRefName(ctx context.Context, pull *issues_model.PullRequest) string {
if err := pull.LoadBaseRepo(ctx); err != nil {
log.Error("LoadBaseRepo: %v", err)
return ""
}
gitRepo, err := gitrepo.OpenRepository(ctx, pull.BaseRepo)
if err != nil {
log.Error("OpenRepository: %v", err)
return ""
}
defer gitRepo.Close()
commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
return ""
}
return commitID
}

View file

@ -14,19 +14,10 @@
{{end}} {{end}}
{{end}} {{end}}
<div class="ui top attached header clearing segment tw-relative commit-header {{$class}}"> <div class="ui top attached header clearing segment tw-relative commit-header {{$class}}">
<div class="tw-flex tw-mb-4 tw-gap-1 max-sm:tw-flex-col"> <div class="tw-flex tw-mb-4 tw-gap-1">
<h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3> <h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3>
<div class="commit-header-buttons"> {{if not $.PageIsWiki}}
{{if .PageIsPullFiles}} <div class="commit-header-buttons">
<div class="ui buttons">
<a class="ui small button {{if .PrevCommitLink}}" href="{{.PrevCommitLink}}"{{else}}disabled"{{end}}>
{{svg "octicon-chevron-left"}} {{ctx.Locale.Tr "repo.diff.commit.previous-short"}}
</a>
<a class="ui small button {{if .NextCommitLink}}" href="{{.NextCommitLink}}"{{else}}disabled"{{end}}>
{{ctx.Locale.Tr "repo.diff.commit.next-short"}} {{svg "octicon-chevron-right"}}
</a>
</div>
{{else if not $.PageIsWiki}}
<a class="ui primary tiny button" href="{{.SourcePath}}"> <a class="ui primary tiny button" href="{{.SourcePath}}">
{{ctx.Locale.Tr "repo.diff.browse_source"}} {{ctx.Locale.Tr "repo.diff.browse_source"}}
</a> </a>
@ -141,8 +132,8 @@
</div> </div>
</div> </div>
{{end}} {{end}}
{{end}} </div>
</div> {{end}}
</div> </div>
{{if IsMultilineCommitMessage .Commit.Message}} {{if IsMultilineCommitMessage .Commit.Message}}
<pre class="commit-body">{{RenderCommitBody $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</pre> <pre class="commit-body">{{RenderCommitBody $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</pre>
@ -194,16 +185,9 @@
{{end}} {{end}}
<div class="item"> <div class="item">
<span>{{ctx.Locale.Tr "repo.diff.commit"}}</span> <span>{{ctx.Locale.Tr "repo.diff.commit"}}</span>
{{if .PageIsPullFiles}} <span class="ui primary sha label">
{{$commitShaLink := (printf "%s/commit/%s" $.RepoLink (PathEscape .CommitID))}} <span class="shortsha">{{ShortSha .CommitID}}</span>
<a href="{{$commitShaLink}}" class="ui primary sha label"> </span>
<span class="shortsha">{{ShortSha .CommitID}}</span>
</a>
{{else}}
<span class="ui primary sha label">
<span class="shortsha">{{ShortSha .CommitID}}</span>
</span>
{{end}}
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
{{if not (or .PageIsWiki .PageIsPullFiles)}} {{if not .PageIsWiki}}
<div class="branch-and-tag-area" data-text-default-branch-tooltip="{{ctx.Locale.Tr "repo.commit.contained_in_default_branch"}}"> <div class="branch-and-tag-area" data-text-default-branch-tooltip="{{ctx.Locale.Tr "repo.commit.contained_in_default_branch"}}">
<button class="ui button ellipsis-button load-branches-and-tags tw-mt-2" aria-expanded="false" <button class="ui button ellipsis-button load-branches-and-tags tw-mt-2" aria-expanded="false"
data-fetch-url="{{.RepoLink}}/commit/{{.CommitID}}/load-branches-and-tags" data-fetch-url="{{.RepoLink}}/commit/{{.CommitID}}/load-branches-and-tags"

View file

@ -49,9 +49,6 @@
<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji $.Context}}</span> <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji $.Context}}</span>
{{else}} {{else}}
{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}}
{{if $.PageIsPullCommits}}
{{$commitLink = (printf "%s/pulls/%d/commits/%s" $commitRepoLink $.Issue.Index (PathEscape .ID.String))}}
{{end}}
<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitLink ($.Repository.ComposeMetas ctx)}}</span> <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitLink ($.Repository.ComposeMetas ctx)}}</span>
{{end}} {{end}}
</span> </span>

View file

@ -11,14 +11,7 @@
{{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 20}} {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 20}}
{{end}} {{end}}
{{$commitLink := printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String)}} {{$commitLink:= printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String)}}
{{/* Only link those commits in the file diff view that can actually be reviewed there.
A force push or other rewriting of history will cause a commit to not be
part of the pull request anymore. */}}
{{if index $.root.CommitIDs .ID.String}}
{{$commitLink = printf "%s/pulls/%d/commits/%s" $.comment.Issue.PullRequest.BaseRepo.Link $.comment.Issue.Index (PathEscape .ID.String)}}
{{end}}
<span class="tw-flex-1 tw-font-mono gt-ellipsis" title="{{.Summary}}"> <span class="tw-flex-1 tw-font-mono gt-ellipsis" title="{{.Summary}}">
{{- RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}} {{- RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}}

View file

@ -53,7 +53,7 @@
{{if not .DiffNotAvailable}} {{if not .DiffNotAvailable}}
{{if and .IsShowingOnlySingleCommit .PageIsPullFiles}} {{if and .IsShowingOnlySingleCommit .PageIsPullFiles}}
<div class="ui info message"> <div class="ui info message">
<div>{{ctx.Locale.Tr "repo.pulls.showing_only_single_commit" (ShortSha .CommitID)}} - <a href="{{$.Issue.Link}}/files?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated={{$.ShowOutdatedComments}}">{{ctx.Locale.Tr "repo.pulls.show_all_commits"}}</a></div> <div>{{ctx.Locale.Tr "repo.pulls.showing_only_single_commit" (ShortSha .AfterCommitID)}} - <a href="{{$.Issue.Link}}/files?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated={{$.ShowOutdatedComments}}">{{ctx.Locale.Tr "repo.pulls.show_all_commits"}}</a></div>
</div> </div>
{{else if and (not .IsShowingAllCommits) .PageIsPullFiles}} {{else if and (not .IsShowingAllCommits) .PageIsPullFiles}}
<div class="ui info message"> <div class="ui info message">
@ -93,12 +93,6 @@
if (diffTreeVisible) document.getElementById('diff-file-tree').classList.remove('tw-hidden'); if (diffTreeVisible) document.getElementById('diff-file-tree').classList.remove('tw-hidden');
</script> </script>
{{end}} {{end}}
<div id="diff-content-container">
{{if .IsShowingOnlySingleCommit}}
<div id="diff-commit-header">
{{template "repo/commit_header" .}}
</div>
{{end}}
{{if .DiffNotAvailable}} {{if .DiffNotAvailable}}
<h4>{{ctx.Locale.Tr "repo.diff.data_not_available"}}</h4> <h4>{{ctx.Locale.Tr "repo.diff.data_not_available"}}</h4>
{{else}} {{else}}
@ -236,7 +230,6 @@
{{end}} {{end}}
</div> </div>
{{end}} {{end}}
</div>
</div> </div>
{{if and (not $.Repository.IsArchived) (not .DiffNotAvailable)}} {{if and (not $.Repository.IsArchived) (not .DiffNotAvailable)}}

View file

@ -1,14 +1,17 @@
<div id="review-box"> <div id="review-box">
<div <div
{{if .Repository.IsArchived}} {{if not $.IsShowingAllCommits}}
data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.review_only_possible_for_full_diff"}}"
{{else if .Repository.IsArchived}}
data-tooltip-content="{{ctx.Locale.Tr "repo.archive.pull.noreview"}}" data-tooltip-content="{{ctx.Locale.Tr "repo.archive.pull.noreview"}}"
{{end}}> {{end}}>
<button class="ui tiny primary button tw-pr-1 tw-flex js-btn-review {{if .Repository.IsArchived}}disabled{{end}}"> <button class="ui tiny primary button tw-pr-1 tw-flex js-btn-review {{if or (not $.IsShowingAllCommits) .Repository.IsArchived}}disabled{{end}}">
{{ctx.Locale.Tr "repo.diff.review"}} {{ctx.Locale.Tr "repo.diff.review"}}
<span class="ui small label review-comments-counter" data-pending-comment-number="{{.PendingCodeCommentNumber}}">{{.PendingCodeCommentNumber}}</span> <span class="ui small label review-comments-counter" data-pending-comment-number="{{.PendingCodeCommentNumber}}">{{.PendingCodeCommentNumber}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
</button> </button>
</div> </div>
{{if $.IsShowingAllCommits}}
<div class="review-box-panel tippy-target"> <div class="review-box-panel tippy-target">
<div class="ui segment"> <div class="ui segment">
<form class="ui form form-fetch-action" action="{{.Link}}/reviews/submit" method="post"> <form class="ui form form-fetch-action" action="{{.Link}}/reviews/submit" method="post">
@ -52,4 +55,5 @@
</form> </form>
</div> </div>
</div> </div>
{{end}}
</div> </div>

View file

@ -12994,7 +12994,6 @@
"enum": [ "enum": [
"oldest", "oldest",
"recentupdate", "recentupdate",
"recentclose",
"leastupdate", "leastupdate",
"mostcomment", "mostcomment",
"leastcomment", "leastcomment",

View file

@ -82,7 +82,7 @@ func newRepo(t *testing.T, userID int64, repoName string, fileChanges []FileChan
for _, file := range fileChanges { for _, file := range fileChanges {
for i, version := range file.Versions { for i, version := range file.Versions {
operation := "update" operation := "update"
if i == 0 { if i == 0 && file.Filename != "README.md" {
operation = "create" operation = "create"
} }

View file

@ -11,7 +11,7 @@ import {save_visual, test} from './utils_e2e.ts';
test.use({user: 'user2'}); test.use({user: 'user2'});
test('PR: Create review from files', async ({page}) => { test('PR: Finish review', async ({page}) => {
const response = await page.goto('/user2/repo1/pulls/5/files'); const response = await page.goto('/user2/repo1/pulls/5/files');
expect(response?.status()).toBe(200); expect(response?.status()).toBe(200);
@ -22,93 +22,4 @@ test('PR: Create review from files', async ({page}) => {
await page.locator('#review-box .js-btn-review').click(); await page.locator('#review-box .js-btn-review').click();
await expect(page.locator('.tippy-box .review-box-panel')).toBeVisible(); await expect(page.locator('.tippy-box .review-box-panel')).toBeVisible();
await save_visual(page); await save_visual(page);
await page.locator('.review-box-panel textarea#_combo_markdown_editor_0')
.fill('This is a review');
await page.locator('.review-box-panel button.btn-submit[value="approve"]').click();
await page.waitForURL(/.*\/user2\/repo1\/pulls\/5#issuecomment-\d+/);
await save_visual(page);
});
test('PR: Create review from commit', async ({page}) => {
const response = await page.goto('/user2/repo1/pulls/3/commits/4a357436d925b5c974181ff12a994538ddc5a269');
expect(response?.status()).toBe(200);
await page.locator('button.add-code-comment').click();
const code_comment = page.locator('.comment-code-cloud form textarea.markdown-text-editor');
await expect(code_comment).toBeVisible();
await code_comment.fill('This is a code comment');
await save_visual(page);
const start_button = page.locator('.comment-code-cloud form button.btn-start-review');
// Workaround for #7152, where there might already be a pending review state from previous
// test runs (most likely to happen when debugging tests).
if (await start_button.isVisible({timeout: 100})) {
await start_button.click();
} else {
await page.locator('.comment-code-cloud form button.btn-add-comment').click();
}
await expect(page.locator('.comment-list .comment-container')).toBeVisible();
// We need to wait for the review to be processed. Checking the comment counter
// conveniently does that.
await expect(page.locator('#review-box .js-btn-review > span.review-comments-counter')).toHaveText('1');
await page.locator('#review-box .js-btn-review').click();
await expect(page.locator('.tippy-box .review-box-panel')).toBeVisible();
await save_visual(page);
await page.locator('.review-box-panel textarea.markdown-text-editor')
.fill('This is a review');
await page.locator('.review-box-panel button.btn-submit[value="approve"]').click();
await page.waitForURL(/.*\/user2\/repo1\/pulls\/3#issuecomment-\d+/);
await save_visual(page);
// In addition to testing the ability to delete comments, this also
// performs clean up. If tests are run for multiple platforms, the data isn't reset
// in-between, and subsequent runs of this test would fail, because when there already is
// a comment, the on-hover button to start a conversation doesn't appear anymore.
await page.goto('/user2/repo1/pulls/3/commits/4a357436d925b5c974181ff12a994538ddc5a269');
await page.locator('.comment-header-right.actions a.context-menu').click();
await expect(page.locator('.comment-header-right.actions div.menu').getByText(/Copy link.*/)).toBeVisible();
// The button to delete a comment will prompt for confirmation using a browser alert.
page.on('dialog', (dialog) => dialog.accept());
await page.locator('.comment-header-right.actions div.menu .delete-comment').click();
await expect(page.locator('.comment-list .comment-container')).toBeHidden();
await save_visual(page);
});
test('PR: Navigate by single commit', async ({page}) => {
const response = await page.goto('/user2/repo1/pulls/3/commits');
expect(response?.status()).toBe(200);
await page.locator('tbody.commit-list td.message a').nth(1).click();
await page.waitForURL(/.*\/user2\/repo1\/pulls\/3\/commits\/4a357436d925b5c974181ff12a994538ddc5a269/);
await save_visual(page);
let prevButton = page.locator('.commit-header-buttons').getByText(/Prev/);
let nextButton = page.locator('.commit-header-buttons').getByText(/Next/);
await prevButton.waitFor();
await nextButton.waitFor();
await expect(prevButton).toHaveClass(/disabled/);
await expect(nextButton).not.toHaveClass(/disabled/);
await expect(nextButton).toHaveAttribute('href', '/user2/repo1/pulls/3/commits/5f22f7d0d95d614d25a5b68592adb345a4b5c7fd');
await nextButton.click();
await page.waitForURL(/.*\/user2\/repo1\/pulls\/3\/commits\/5f22f7d0d95d614d25a5b68592adb345a4b5c7fd/);
await save_visual(page);
prevButton = page.locator('.commit-header-buttons').getByText(/Prev/);
nextButton = page.locator('.commit-header-buttons').getByText(/Next/);
await prevButton.waitFor();
await nextButton.waitFor();
await expect(prevButton).not.toHaveClass(/disabled/);
await expect(nextButton).toHaveClass(/disabled/);
await expect(prevButton).toHaveAttribute('href', '/user2/repo1/pulls/3/commits/4a357436d925b5c974181ff12a994538ddc5a269');
}); });

View file

@ -1,2 +1 @@
0000000000000000000000000000000000000000 1978192d98bb1b65e11c2cf37da854fbf94bffd6 Gitea <gitea@fake.local> 1688672383 +0200 push 0000000000000000000000000000000000000000 1978192d98bb1b65e11c2cf37da854fbf94bffd6 Gitea <gitea@fake.local> 1688672383 +0200 push
1978192d98bb1b65e11c2cf37da854fbf94bffd6 9b93963cf6de4dc33f915bb67f192d099c301f43 Forgejo <forgejo@fake.local> 1749737639 +0200 push

View file

@ -1 +1 @@
9b93963cf6de4dc33f915bb67f192d099c301f43 1978192d98bb1b65e11c2cf37da854fbf94bffd6

View file

@ -1 +1 @@
9b93963cf6de4dc33f915bb67f192d099c301f43 1978192d98bb1b65e11c2cf37da854fbf94bffd6

View file

@ -71,11 +71,11 @@ TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test?multiStatements=true TEST_
### Run pgsql integration tests ### Run pgsql integration tests
Setup a pgsql database inside docker Setup a pgsql database inside docker
``` ```
docker run -e "POSTGRES_DB=test" -e POSTGRES_PASSWORD=postgres POSTGRESQL_FSYNC=off POSTGRESQL_EXTRA_FLAGS="-c full_page_writes=off" -p 5432:5432 --rm --name pgsql data.forgejo.org/oci/bitnami/postgresql:16 #(Ctrl-c to stop the database) docker run -e "POSTGRES_DB=test" -e POSTGRES_PASSWORD=postgres -p 5432:5432 --rm --name pgsql postgres:latest #(Ctrl-c to stop the database)
``` ```
Start tests based on the database container Start tests based on the database container
``` ```
TEST_STORAGE_TYPE=local TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make 'test-pgsql#Test' TEST_STORAGE_TYPE=local TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
``` ```
### Running individual tests ### Running individual tests

View file

@ -4,7 +4,6 @@
package integration package integration
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
@ -21,10 +20,7 @@ import (
user_model "forgejo.org/models/user" user_model "forgejo.org/models/user"
"forgejo.org/modules/git" "forgejo.org/modules/git"
"forgejo.org/modules/optional" "forgejo.org/modules/optional"
"forgejo.org/modules/test"
pull_service "forgejo.org/services/pull"
files_service "forgejo.org/services/repository/files" files_service "forgejo.org/services/repository/files"
shared_automerge "forgejo.org/services/shared/automerge"
"forgejo.org/tests" "forgejo.org/tests"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -55,20 +51,6 @@ func TestPatchStatus(t *testing.T) {
}) })
defer f() defer f()
testAutomergeQueued := func(t *testing.T, pr *issues_model.PullRequest, expected issues_model.PullRequestStatus) {
t.Helper()
var actual issues_model.PullRequestStatus = -1
defer test.MockVariableValue(&shared_automerge.AddToQueueIfMergeable, func(ctx context.Context, pull *issues_model.PullRequest) {
actual = pull.Status
})()
pull_service.AddToTaskQueue(t.Context(), pr)
assert.Eventually(t, func() bool {
return expected == actual
}, time.Second*5, time.Millisecond*200)
}
testRepoFork(t, session, "user2", repo.Name, "org3", "forked-repo") testRepoFork(t, session, "user2", repo.Name, "org3", "forked-repo")
forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "org3", Name: "forked-repo"}) forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "org3", Name: "forked-repo"})
@ -109,9 +91,7 @@ func TestPatchStatus(t *testing.T) {
require.NoError(t, git.NewCommand(t.Context(), "push", "fork", "HEAD:normal").Run(&git.RunOpts{Dir: dstPath})) require.NoError(t, git.NewCommand(t.Context(), "push", "fork", "HEAD:normal").Run(&git.RunOpts{Dir: dstPath}))
testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkRepo.OwnerName, forkRepo.Name, "normal", "across repo normal") testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkRepo.OwnerName, forkRepo.Name, "normal", "across repo normal")
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkRepo.ID, HeadBranch: "normal"}, "flow = 0") test(t, unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkRepo.ID, HeadBranch: "normal"}, "flow = 0"))
test(t, pr)
testAutomergeQueued(t, pr, issues_model.PullRequestStatusMergeable)
}) })
t.Run("Same repository", func(t *testing.T) { t.Run("Same repository", func(t *testing.T) {
@ -164,9 +144,7 @@ func TestPatchStatus(t *testing.T) {
t.Run("Existing", func(t *testing.T) { t.Run("Existing", func(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkRepo.ID, HeadBranch: "normal"}, "flow = 0") test(t, unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkRepo.ID, HeadBranch: "normal"}, "flow = 0"))
test(t, pr)
testAutomergeQueued(t, pr, issues_model.PullRequestStatusConflict)
}) })
t.Run("New", func(t *testing.T) { t.Run("New", func(t *testing.T) {

View file

@ -31,20 +31,3 @@ func TestListPullCommits(t *testing.T) {
} }
assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha) assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha)
} }
func TestPullCommitLinks(t *testing.T) {
defer tests.PrepareTestEnv(t)()
req := NewRequest(t, "GET", "/user2/repo1/pulls/3/commits")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
commitSha := htmlDoc.Find(".commit-list td.sha a.sha.label").First()
commitShaHref, _ := commitSha.Attr("href")
assert.Equal(t, "/user2/repo1/pulls/3/commits/5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commitShaHref)
commitLink := htmlDoc.Find(".commit-list td.message a").First()
commitLinkHref, _ := commitLink.Attr("href")
assert.Equal(t, "/user2/repo1/pulls/3/commits/5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commitLinkHref)
}

View file

@ -14,22 +14,22 @@ import (
) )
func TestPullDiff_CompletePRDiff(t *testing.T) { func TestPullDiff_CompletePRDiff(t *testing.T) {
doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files", []string{"test1.txt", "test10.txt", "test2.txt", "test3.txt", "test4.txt", "test5.txt", "test6.txt", "test7.txt", "test8.txt", "test9.txt"}) doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files", false, []string{"test1.txt", "test10.txt", "test2.txt", "test3.txt", "test4.txt", "test5.txt", "test6.txt", "test7.txt", "test8.txt", "test9.txt"})
} }
func TestPullDiff_SingleCommitPRDiff(t *testing.T) { func TestPullDiff_SingleCommitPRDiff(t *testing.T) {
doTestPRDiff(t, "/user2/commitsonpr/pulls/1/commits/c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2", []string{"test3.txt"}) doTestPRDiff(t, "/user2/commitsonpr/pulls/1/commits/c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2", true, []string{"test3.txt"})
} }
func TestPullDiff_CommitRangePRDiff(t *testing.T) { func TestPullDiff_CommitRangePRDiff(t *testing.T) {
doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files/4ca8bcaf27e28504df7bf996819665986b01c847..23576dd018294e476c06e569b6b0f170d0558705", []string{"test2.txt", "test3.txt", "test4.txt"}) doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files/4ca8bcaf27e28504df7bf996819665986b01c847..23576dd018294e476c06e569b6b0f170d0558705", true, []string{"test2.txt", "test3.txt", "test4.txt"})
} }
func TestPullDiff_StartingFromBaseToCommitPRDiff(t *testing.T) { func TestPullDiff_StartingFromBaseToCommitPRDiff(t *testing.T) {
doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files/c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2", []string{"test1.txt", "test2.txt", "test3.txt"}) doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files/c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2", true, []string{"test1.txt", "test2.txt", "test3.txt"})
} }
func doTestPRDiff(t *testing.T, prDiffURL string, expectedFilenames []string) { func doTestPRDiff(t *testing.T, prDiffURL string, reviewBtnDisabled bool, expectedFilenames []string) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2") session := loginUser(t, "user2")
@ -52,4 +52,7 @@ func doTestPRDiff(t *testing.T, prDiffURL string, expectedFilenames []string) {
filename, _ := s.Attr("data-old-filename") filename, _ := s.Attr("data-old-filename")
assert.Equal(t, expectedFilenames[i], filename) assert.Equal(t, expectedFilenames[i], filename)
}) })
// Ensure the review button is enabled for full PR reviews
assert.Equal(t, reviewBtnDisabled, doc.doc.Find(".js-btn-review").HasClass("disabled"))
} }

View file

@ -1,106 +0,0 @@
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"net/http"
"strings"
"testing"
"time"
repo_model "forgejo.org/models/repo"
"forgejo.org/models/unittest"
"forgejo.org/modules/git"
"forgejo.org/tests"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPullFilesCommitHeader(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("Verify commit info", func(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
require.NoError(t, err)
defer gitRepo.Close()
commit, err := gitRepo.GetCommit("62fb502a7172d4453f0322a2cc85bddffa57f07a")
require.NoError(t, err)
req := NewRequest(t, "GET", "/user2/repo1/pulls/5/commits/62fb502a7172d4453f0322a2cc85bddffa57f07a")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
header := htmlDoc.doc.Find("#diff-commit-header")
summary := header.Find(".commit-header h3")
assert.Equal(t, commit.Summary(), strings.TrimSpace(summary.Text()))
author := header.Find(".author strong")
assert.Equal(t, commit.Author.Name, author.Text())
date, _ := header.Find("#authored-time relative-time").Attr("datetime")
assert.Equal(t, commit.Author.When.Format(time.RFC3339), date)
sha := header.Find(".commit-header-row .sha.label")
shaHref, _ := sha.Attr("href")
assert.Equal(t, commit.ID.String()[:10], sha.Find(".shortsha").Text())
assert.Equal(t, "/user2/repo1/commit/62fb502a7172d4453f0322a2cc85bddffa57f07a", shaHref)
})
t.Run("Navigation", func(t *testing.T) {
t.Run("No previous on first commit", func(t *testing.T) {
req := NewRequest(t, "GET", "/user2/commitsonpr/pulls/1/commits/4ca8bcaf27e28504df7bf996819665986b01c847")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
buttons := htmlDoc.doc.Find(".commit-header-buttons a.small.button")
assert.Equal(t, 2, buttons.Length(), "expected two buttons in commit header")
assert.True(t, buttons.First().HasClass("disabled"), "'prev' button should be disabled")
assert.False(t, buttons.Last().HasClass("disabled"), "'next' button should not be disabled")
href, _ := buttons.Last().Attr("href")
assert.Equal(t, "/user2/commitsonpr/pulls/1/commits/96cef4a7b72b3c208340ae6f0cf55a93e9077c93", href)
})
t.Run("No next on last commit", func(t *testing.T) {
req := NewRequest(t, "GET", "/user2/commitsonpr/pulls/1/commits/9b93963cf6de4dc33f915bb67f192d099c301f43")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
buttons := htmlDoc.doc.Find(".commit-header-buttons a.small.button")
assert.Equal(t, 2, buttons.Length(), "expected two buttons in commit header")
assert.False(t, buttons.First().HasClass("disabled"), "'prev' button should not be disabled")
assert.True(t, buttons.Last().HasClass("disabled"), "'next' button should be disabled")
href, _ := buttons.First().Attr("href")
assert.Equal(t, "/user2/commitsonpr/pulls/1/commits/2d65d92dc800c6f448541240c18e82bf36b954bb", href)
})
t.Run("Both directions on middle commit", func(t *testing.T) {
req := NewRequest(t, "GET", "/user2/commitsonpr/pulls/1/commits/c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
buttons := htmlDoc.doc.Find(".commit-header-buttons a.small.button")
assert.Equal(t, 2, buttons.Length(), "expected two buttons in commit header")
assert.False(t, buttons.First().HasClass("disabled"), "'prev' button should not be disabled")
assert.False(t, buttons.Last().HasClass("disabled"), "'next' button should not be disabled")
href, _ := buttons.First().Attr("href")
assert.Equal(t, "/user2/commitsonpr/pulls/1/commits/96cef4a7b72b3c208340ae6f0cf55a93e9077c93", href)
href, _ = buttons.Last().Attr("href")
assert.Equal(t, "/user2/commitsonpr/pulls/1/commits/23576dd018294e476c06e569b6b0f170d0558705", href)
})
})
}

View file

@ -30,43 +30,6 @@ func TestViewPulls(t *testing.T) {
assert.Equal(t, "Search pulls…", placeholder) assert.Equal(t, "Search pulls…", placeholder)
} }
func TestPullViewConversation(t *testing.T) {
defer tests.PrepareTestEnv(t)()
req := NewRequest(t, "GET", "/user2/commitsonpr/pulls/1")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
t.Run("Commits", func(t *testing.T) {
commitLists := htmlDoc.Find(".timeline-item.commits-list")
assert.Equal(t, 4, commitLists.Length())
commits := commitLists.Find(".singular-commit")
assert.Equal(t, 10, commits.Length())
// First one has not been affected by a force push, therefore it's still part of the
// PR and should link to the PR-scoped review tab
firstCommit := commits.Eq(0)
firstCommitMessageHref, _ := firstCommit.Find("a.default-link").Attr("href")
firstCommitShaHref, _ := firstCommit.Find("a.sha.label").Attr("href")
assert.Equal(t, "/user2/commitsonpr/pulls/1/commits/4ca8bcaf27e28504df7bf996819665986b01c847", firstCommitMessageHref)
assert.Equal(t, "/user2/commitsonpr/pulls/1/commits/4ca8bcaf27e28504df7bf996819665986b01c847", firstCommitShaHref)
// The fifth commit has been overwritten by a force push.
// Attempting to view the old one in the review tab won't work:
req := NewRequest(t, "GET", "/user2/commitsonpr/pulls/1/commits/3e64625bd6eb5bcba69ac97de6c8f507402df861")
MakeRequest(t, req, http.StatusNotFound)
// Therefore, this commit should link to the non-PR commit view instead
fifthCommit := commits.Eq(4)
fifthCommitMessageHref, _ := fifthCommit.Find("a.default-link").Attr("href")
fifthCommitShaHref, _ := fifthCommit.Find("a.sha.label").Attr("href")
assert.Equal(t, "/user2/commitsonpr/commit/3e64625bd6eb5bcba69ac97de6c8f507402df861", fifthCommitMessageHref)
assert.Equal(t, "/user2/commitsonpr/commit/3e64625bd6eb5bcba69ac97de6c8f507402df861", fifthCommitShaHref)
})
}
func TestPullManuallyMergeWarning(t *testing.T) { func TestPullManuallyMergeWarning(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()

View file

@ -15,7 +15,6 @@ import (
repo_model "forgejo.org/models/repo" repo_model "forgejo.org/models/repo"
"forgejo.org/models/unittest" "forgejo.org/models/unittest"
user_model "forgejo.org/models/user" user_model "forgejo.org/models/user"
"forgejo.org/modules/git"
"forgejo.org/modules/optional" "forgejo.org/modules/optional"
"forgejo.org/modules/setting" "forgejo.org/modules/setting"
"forgejo.org/modules/test" "forgejo.org/modules/test"
@ -44,13 +43,9 @@ func assertRepoCreateForm(t *testing.T, htmlDoc *HTMLDoc, owner *user_model.User
// the template menu is loaded client-side, so don't assert the option exists // the template menu is loaded client-side, so don't assert the option exists
assert.Equal(t, templateID, htmlDoc.GetInputValueByName("repo_template"), "Unexpected repo_template selection") assert.Equal(t, templateID, htmlDoc.GetInputValueByName("repo_template"), "Unexpected repo_template selection")
for _, name := range []string{"issue_labels", "gitignores", "license"} { for _, name := range []string{"issue_labels", "gitignores", "license", "object_format_name"} {
htmlDoc.AssertDropdownHasOptions(t, name) htmlDoc.AssertDropdownHasOptions(t, name)
} }
if git.SupportHashSha256 {
htmlDoc.AssertDropdownHasOptions(t, "object_format_name")
}
} }
func testRepoGenerate(t *testing.T, session *TestSession, templateID, templateOwnerName, templateRepoName string, user, generateOwner *user_model.User, generateRepoName string) { func testRepoGenerate(t *testing.T, session *TestSession, templateID, templateOwnerName, templateRepoName string, user, generateOwner *user_model.User, generateRepoName string) {

23
tools/lint-go-gopls.sh Executable file
View file

@ -0,0 +1,23 @@
#!/bin/bash
set -uo pipefail
cd "$(dirname -- "${BASH_SOURCE[0]}")" && cd ..
IGNORE_PATTERNS=(
"is deprecated" # TODO: fix these
)
# lint all go files with 'gopls check' and look for lines starting with the
# current absolute path, indicating a error was found. This is necessary
# because the tool does not set non-zero exit code when errors are found.
# ref: https://github.com/golang/go/issues/67078
ERROR_LINES=$("$GO" run "$GOPLS_PACKAGE" check "$@" 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}"));
NUM_ERRORS=$(echo -n "$ERROR_LINES" | wc -l)
if [ "$NUM_ERRORS" -eq "0" ]; then
exit 0;
else
echo "$ERROR_LINES"
echo "Found $NUM_ERRORS 'gopls check' errors"
exit 1;
fi

View file

@ -2468,21 +2468,8 @@ tbody.commit-list {
display: flex; display: flex;
} }
#diff-content-container {
flex: 1;
}
#diff-commit-header {
/* Counteract the `+2px` for width in `.segment` */
padding: 0 2px;
}
#diff-commit-header + h4,
#diff-commit-header + #diff-file-boxes {
margin-top: 8px;
}
#diff-file-boxes { #diff-file-boxes {
flex: 1;
max-width: 100%; max-width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;