Skip to content

Commit d677ee8

Browse files
authored
Merge branch 'go-gitea:main' into main
2 parents 8229cd9 + 62b073e commit d677ee8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2589
-342
lines changed

.dockerignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ _test
1414

1515
# MS VSCode
1616
.vscode
17-
__debug_bin
17+
__debug_bin*
1818

1919
# Architecture specific extensions/prefixes
2020
*.[568vq]

docs/content/contributing/guidelines-frontend.en-us.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h
4747
9. Avoid unnecessary `!important` in CSS, add comments to explain why it's necessary if it can't be avoided.
4848
10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event.
4949
11. Custom event names are recommended to use `ce-` prefix.
50-
12. Prefer using Tailwind CSS which is available via `tw-` prefix, e.g. `tw-relative`. Gitea's helper CSS classes use `gt-` prefix (`gt-mono`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
50+
12. Prefer using Tailwind CSS which is available via `tw-` prefix, e.g. `tw-relative`. Gitea's helper CSS classes use `gt-` prefix (`gt-word-break`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
5151
13. Avoid inline scripts & styles as much as possible, it's recommended to put JS code into JS files and use CSS classes. If inline scripts & styles are unavoidable, explain the reason why it can't be avoided.
5252

5353
### Accessibility / ARIA

docs/content/contributing/guidelines-frontend.zh-cn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ HTML 页面由[Go HTML Template](https://pkg.go.dev/html/template)渲染。
4747
9. 避免在 CSS 中使用不必要的`!important`,如果无法避免,添加注释解释为什么需要它。
4848
10. 避免在一个事件监听器中混合不同的事件,优先为每个事件使用独立的事件监听器。
4949
11. 推荐使用自定义事件名称前缀`ce-`
50-
12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-mono`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。
50+
12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-word-break`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。
5151
13. 尽量避免内联脚本和样式,建议将JS代码放入JS文件中并使用CSS类。如果内联脚本和样式不可避免,请解释无法避免的原因。
5252

5353
### 可访问性 / ARIA

models/actions/variable.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ package actions
66
import (
77
"context"
88
"errors"
9-
"fmt"
109
"strings"
1110

1211
"code.gitea.io/gitea/models/db"
1312
"code.gitea.io/gitea/modules/log"
1413
"code.gitea.io/gitea/modules/timeutil"
15-
"code.gitea.io/gitea/modules/util"
1614

1715
"xorm.io/builder"
1816
)
@@ -55,24 +53,24 @@ type FindVariablesOpts struct {
5553
db.ListOptions
5654
OwnerID int64
5755
RepoID int64
56+
Name string
5857
}
5958

6059
func (opts FindVariablesOpts) ToConds() builder.Cond {
6160
cond := builder.NewCond()
61+
// Since we now support instance-level variables,
62+
// there is no need to check for null values for `owner_id` and `repo_id`
6263
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
6364
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
65+
66+
if opts.Name != "" {
67+
cond = cond.And(builder.Eq{"name": strings.ToUpper(opts.Name)})
68+
}
6469
return cond
6570
}
6671

67-
func GetVariableByID(ctx context.Context, variableID int64) (*ActionVariable, error) {
68-
var variable ActionVariable
69-
has, err := db.GetEngine(ctx).Where("id=?", variableID).Get(&variable)
70-
if err != nil {
71-
return nil, err
72-
} else if !has {
73-
return nil, fmt.Errorf("variable with id %d: %w", variableID, util.ErrNotExist)
74-
}
75-
return &variable, nil
72+
func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariable, error) {
73+
return db.Find[ActionVariable](ctx, opts)
7674
}
7775

7876
func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) {
@@ -84,6 +82,13 @@ func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error)
8482
return count != 0, err
8583
}
8684

85+
func DeleteVariable(ctx context.Context, id int64) error {
86+
if _, err := db.DeleteByID[ActionVariable](ctx, id); err != nil {
87+
return err
88+
}
89+
return nil
90+
}
91+
8792
func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) {
8893
variables := map[string]string{}
8994

models/git/commit_status.go

Lines changed: 73 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"code.gitea.io/gitea/modules/translation"
2626

2727
"xorm.io/builder"
28+
"xorm.io/xorm"
2829
)
2930

3031
// CommitStatus holds a single Status of a single Commit
@@ -269,44 +270,48 @@ type CommitStatusIndex struct {
269270

270271
// GetLatestCommitStatus returns all statuses with a unique context for a given commit.
271272
func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) {
272-
ids := make([]int64, 0, 10)
273-
sess := db.GetEngine(ctx).Table(&CommitStatus{}).
274-
Where("repo_id = ?", repoID).And("sha = ?", sha).
275-
Select("max( id ) as id").
276-
GroupBy("context_hash").OrderBy("max( id ) desc")
273+
getBase := func() *xorm.Session {
274+
return db.GetEngine(ctx).Table(&CommitStatus{}).
275+
Where("repo_id = ?", repoID).And("sha = ?", sha)
276+
}
277+
indices := make([]int64, 0, 10)
278+
sess := getBase().Select("max( `index` ) as `index`").
279+
GroupBy("context_hash").OrderBy("max( `index` ) desc")
277280
if !listOptions.IsListAll() {
278281
sess = db.SetSessionPagination(sess, &listOptions)
279282
}
280-
count, err := sess.FindAndCount(&ids)
283+
count, err := sess.FindAndCount(&indices)
281284
if err != nil {
282285
return nil, count, err
283286
}
284-
statuses := make([]*CommitStatus, 0, len(ids))
285-
if len(ids) == 0 {
287+
statuses := make([]*CommitStatus, 0, len(indices))
288+
if len(indices) == 0 {
286289
return statuses, count, nil
287290
}
288-
return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses)
291+
return statuses, count, getBase().And(builder.In("`index`", indices)).Find(&statuses)
289292
}
290293

291294
// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
292295
func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) {
293296
type result struct {
294-
ID int64
297+
Index int64
295298
RepoID int64
296299
}
297300

298301
results := make([]result, 0, len(repoIDsToLatestCommitSHAs))
299302

300-
sess := db.GetEngine(ctx).Table(&CommitStatus{})
303+
getBase := func() *xorm.Session {
304+
return db.GetEngine(ctx).Table(&CommitStatus{})
305+
}
301306

302307
// Create a disjunction of conditions for each repoID and SHA pair
303308
conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs))
304309
for repoID, sha := range repoIDsToLatestCommitSHAs {
305310
conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha})
306311
}
307-
sess = sess.Where(builder.Or(conds...)).
308-
Select("max( id ) as id, repo_id").
309-
GroupBy("context_hash, repo_id").OrderBy("max( id ) desc")
312+
sess := getBase().Where(builder.Or(conds...)).
313+
Select("max( `index` ) as `index`, repo_id").
314+
GroupBy("context_hash, repo_id").OrderBy("max( `index` ) desc")
310315

311316
if !listOptions.IsListAll() {
312317
sess = db.SetSessionPagination(sess, &listOptions)
@@ -317,15 +322,21 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA
317322
return nil, err
318323
}
319324

320-
ids := make([]int64, 0, len(results))
321325
repoStatuses := make(map[int64][]*CommitStatus)
322-
for _, result := range results {
323-
ids = append(ids, result.ID)
324-
}
325326

326-
statuses := make([]*CommitStatus, 0, len(ids))
327-
if len(ids) > 0 {
328-
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
327+
if len(results) > 0 {
328+
statuses := make([]*CommitStatus, 0, len(results))
329+
330+
conds = make([]builder.Cond, 0, len(results))
331+
for _, result := range results {
332+
cond := builder.Eq{
333+
"`index`": result.Index,
334+
"repo_id": result.RepoID,
335+
"sha": repoIDsToLatestCommitSHAs[result.RepoID],
336+
}
337+
conds = append(conds, cond)
338+
}
339+
err = getBase().Where(builder.Or(conds...)).Find(&statuses)
329340
if err != nil {
330341
return nil, err
331342
}
@@ -342,42 +353,43 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA
342353
// GetLatestCommitStatusForRepoCommitIDs returns all statuses with a unique context for a given list of repo-sha pairs
343354
func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, commitIDs []string) (map[string][]*CommitStatus, error) {
344355
type result struct {
345-
ID int64
346-
Sha string
356+
Index int64
357+
SHA string
347358
}
348359

360+
getBase := func() *xorm.Session {
361+
return db.GetEngine(ctx).Table(&CommitStatus{}).Where("repo_id = ?", repoID)
362+
}
349363
results := make([]result, 0, len(commitIDs))
350364

351-
sess := db.GetEngine(ctx).Table(&CommitStatus{})
352-
353-
// Create a disjunction of conditions for each repoID and SHA pair
354365
conds := make([]builder.Cond, 0, len(commitIDs))
355366
for _, sha := range commitIDs {
356367
conds = append(conds, builder.Eq{"sha": sha})
357368
}
358-
sess = sess.Where(builder.Eq{"repo_id": repoID}.And(builder.Or(conds...))).
359-
Select("max( id ) as id, sha").
360-
GroupBy("context_hash, sha").OrderBy("max( id ) desc")
369+
sess := getBase().And(builder.Or(conds...)).
370+
Select("max( `index` ) as `index`, sha").
371+
GroupBy("context_hash, sha").OrderBy("max( `index` ) desc")
361372

362373
err := sess.Find(&results)
363374
if err != nil {
364375
return nil, err
365376
}
366377

367-
ids := make([]int64, 0, len(results))
368378
repoStatuses := make(map[string][]*CommitStatus)
369-
for _, result := range results {
370-
ids = append(ids, result.ID)
371-
}
372379

373-
statuses := make([]*CommitStatus, 0, len(ids))
374-
if len(ids) > 0 {
375-
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
380+
if len(results) > 0 {
381+
statuses := make([]*CommitStatus, 0, len(results))
382+
383+
conds = make([]builder.Cond, 0, len(results))
384+
for _, result := range results {
385+
conds = append(conds, builder.Eq{"`index`": result.Index, "sha": result.SHA})
386+
}
387+
err = getBase().And(builder.Or(conds...)).Find(&statuses)
376388
if err != nil {
377389
return nil, err
378390
}
379391

380-
// Group the statuses by repo ID
392+
// Group the statuses by commit
381393
for _, status := range statuses {
382394
repoStatuses[status.SHA] = append(repoStatuses[status.SHA], status)
383395
}
@@ -388,22 +400,36 @@ func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, co
388400

389401
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
390402
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
403+
type result struct {
404+
Index int64
405+
SHA string
406+
}
407+
getBase := func() *xorm.Session {
408+
return db.GetEngine(ctx).Table(&CommitStatus{}).Where("repo_id = ?", repoID)
409+
}
410+
391411
start := timeutil.TimeStampNow().AddDuration(-before)
392-
ids := make([]int64, 0, 10)
393-
if err := db.GetEngine(ctx).Table("commit_status").
394-
Where("repo_id = ?", repoID).
395-
And("updated_unix >= ?", start).
396-
Select("max( id ) as id").
397-
GroupBy("context_hash").OrderBy("max( id ) desc").
398-
Find(&ids); err != nil {
412+
results := make([]result, 0, 10)
413+
414+
sess := getBase().And("updated_unix >= ?", start).
415+
Select("max( `index` ) as `index`, sha").
416+
GroupBy("context_hash, sha").OrderBy("max( `index` ) desc")
417+
418+
err := sess.Find(&results)
419+
if err != nil {
399420
return nil, err
400421
}
401422

402-
contexts := make([]string, 0, len(ids))
403-
if len(ids) == 0 {
423+
contexts := make([]string, 0, len(results))
424+
if len(results) == 0 {
404425
return contexts, nil
405426
}
406-
return contexts, db.GetEngine(ctx).Select("context").Table("commit_status").In("id", ids).Find(&contexts)
427+
428+
conds := make([]builder.Cond, 0, len(results))
429+
for _, result := range results {
430+
conds = append(conds, builder.Eq{"`index`": result.Index, "sha": result.SHA})
431+
}
432+
return contexts, getBase().And(builder.Or(conds...)).Select("context").Find(&contexts)
407433
}
408434

409435
// NewCommitStatusOptions holds options for creating a CommitStatus

models/issues/review.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,23 @@ func (err ErrNotValidReviewRequest) Unwrap() error {
6666
return util.ErrInvalidArgument
6767
}
6868

69+
// ErrReviewRequestOnClosedPR represents an error when an user tries to request a re-review on a closed or merged PR.
70+
type ErrReviewRequestOnClosedPR struct{}
71+
72+
// IsErrReviewRequestOnClosedPR checks if an error is an ErrReviewRequestOnClosedPR.
73+
func IsErrReviewRequestOnClosedPR(err error) bool {
74+
_, ok := err.(ErrReviewRequestOnClosedPR)
75+
return ok
76+
}
77+
78+
func (err ErrReviewRequestOnClosedPR) Error() string {
79+
return "cannot request a re-review on a closed or merged PR"
80+
}
81+
82+
func (err ErrReviewRequestOnClosedPR) Unwrap() error {
83+
return util.ErrPermissionDenied
84+
}
85+
6986
// ReviewType defines the sort of feedback a review gives
7087
type ReviewType int
7188

@@ -618,9 +635,24 @@ func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_mo
618635
return nil, err
619636
}
620637

621-
// skip it when reviewer hase been request to review
622-
if review != nil && review.Type == ReviewTypeRequest {
623-
return nil, committer.Commit() // still commit the transaction, or committer.Close() will rollback it, even if it's a reused transaction.
638+
if review != nil {
639+
// skip it when reviewer hase been request to review
640+
if review.Type == ReviewTypeRequest {
641+
return nil, committer.Commit() // still commit the transaction, or committer.Close() will rollback it, even if it's a reused transaction.
642+
}
643+
644+
if issue.IsClosed {
645+
return nil, ErrReviewRequestOnClosedPR{}
646+
}
647+
648+
if issue.IsPull {
649+
if err := issue.LoadPullRequest(ctx); err != nil {
650+
return nil, err
651+
}
652+
if issue.PullRequest.HasMerged {
653+
return nil, ErrReviewRequestOnClosedPR{}
654+
}
655+
}
624656
}
625657

626658
// if the reviewer is an official reviewer,

models/issues/review_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,33 @@ func TestDeleteDismissedReview(t *testing.T) {
288288
assert.NoError(t, issues_model.DeleteReview(db.DefaultContext, review))
289289
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
290290
}
291+
292+
func TestAddReviewRequest(t *testing.T) {
293+
assert.NoError(t, unittest.PrepareTestDatabase())
294+
295+
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
296+
assert.NoError(t, pull.LoadIssue(db.DefaultContext))
297+
issue := pull.Issue
298+
assert.NoError(t, issue.LoadRepo(db.DefaultContext))
299+
reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
300+
_, err := issues_model.CreateReview(db.DefaultContext, issues_model.CreateReviewOptions{
301+
Issue: issue,
302+
Reviewer: reviewer,
303+
Type: issues_model.ReviewTypeReject,
304+
})
305+
306+
assert.NoError(t, err)
307+
pull.HasMerged = false
308+
assert.NoError(t, pull.UpdateCols(db.DefaultContext, "has_merged"))
309+
issue.IsClosed = true
310+
_, err = issues_model.AddReviewRequest(db.DefaultContext, issue, reviewer, &user_model.User{})
311+
assert.Error(t, err)
312+
assert.True(t, issues_model.IsErrReviewRequestOnClosedPR(err))
313+
314+
pull.HasMerged = true
315+
assert.NoError(t, pull.UpdateCols(db.DefaultContext, "has_merged"))
316+
issue.IsClosed = false
317+
_, err = issues_model.AddReviewRequest(db.DefaultContext, issue, reviewer, &user_model.User{})
318+
assert.Error(t, err)
319+
assert.True(t, issues_model.IsErrReviewRequestOnClosedPR(err))
320+
}

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,8 @@ var migrations = []Migration{
569569
// v291 -> v292
570570
NewMigration("Add Index to attachment.comment_id", v1_22.AddCommentIDIndexofAttachment),
571571
// v292 -> v293
572+
NewMigration("Ensure every project has exactly one default column - No Op", noopMigration),
573+
// v293 -> v294
572574
NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency),
573575
}
574576

0 commit comments

Comments
 (0)