Compare commits

...

20 Commits

Author SHA1 Message Date
Thomas E Lackey
4db82002a2
Merge f54af1e44c6aec49c36d26f2c046775f6c9a15ee into 21af8150b7ba315a9f75264ab77813b0b7c697a8 2025-02-20 08:43:16 +08:00
GiteaBot
21af8150b7 [skip ci] Updated translations via Crowdin 2025-02-20 00:32:10 +00:00
Thomas E Lackey
f54af1e44c
Merge branch 'main' into telackey/sort 2025-02-19 16:07:48 -06:00
ericLemanissier
40faa6dc78
git graph: don't show detached commits (#33645)
Some checks failed
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-docker-rootful (push) Has been cancelled
release-nightly / nightly-docker-rootless (push) Has been cancelled
Current git graph is not usable for mirrors of repos having a lot of
PRs, as can be seen at
https://demo.gitea.com/ericLemanissier/conan-center-index/graph

![image](https://github.com/user-attachments/assets/ace40dd2-3eea-4d69-8e19-10fb7224e326)


Manually running `git log --graph --date-order --all` on such a repo
indeed shows:
```
*   commit c4a34bd39d7977c8630177c5f88507000ea3e943
|\  Merge: a4bbd3ad6b 35a102c77c
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 08:36:41 2025 +0000
| |
| |     Merge 35a102c77cbc38d84baca0ca63466fb410336ea8 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| |
| * commit 35a102c77cbc38d84baca0ca63466fb410336ea8
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 17:36:35 2025 +0900
| |
| |     update 4.4.2
| |
| | * commit 5d610f4fd3c0428731e402a2f618fad9ce055875
| |/| Merge: a4bbd3ad6b fe916fb70a
|/| | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:30 2025 +0000
| | |
| | |     Merge fe916fb70a8bf49503cce70a5c7124bcc4314ddc into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | |
| | * commit fe916fb70a8bf49503cce70a5c7124bcc4314ddc
| | | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:18 2025 +0000
| | |
| | |     Remove parquet cmakelist patch
| | |
| | | * commit 9f6d2759d650ec3c86d01bb940e829e7e14220c2
| |_|/| Merge: a4bbd3ad6b f0963429b0
|/| | | Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
| | | | Date:   Wed Feb 19 08:03:08 2025 +0100
| | | |
| | | |     Merge f0963429b0952499da0da7e559f8d53387097307 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | | |
| | | * commit f0963429b0952499da0da7e559f8d53387097307
| |_|/  Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
|/| |   Date:   Wed Feb 19 08:01:43 2025 +0100
| | |
| | |       added cwt-cucumber 2.5
| | |
```

On the other hand, running `git log --graph --date-order --branches
--tags` returns the expected:
```
* commit a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98 (HEAD -> master)
| Author: Dan <mstr.danila@gmail.com>
| Date:   Fri Feb 14 18:46:11 2025 +0200
|
|     grpc: add version 1.69.0 (#26446)
|
|     * grpc: add version 1.69.0
|
|     * add cmake tool requires
|
|     ---------
|
|     Co-authored-by: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
|
* commit a7868807cb2e21206ebf95278cb588f29a3e2205
| Author: Guillaume Egles <gegles@users.noreply.github.com>
| Date:   Thu Feb 13 05:44:35 2025 -0800
|
|     openssl: add versions `3.0.16`, `3.1.8`, `3.2.4`, `3.3.3`, `3.4.1`, stop publishing revisions for version `3.0.15` (#26578)
|
* commit 86057d3e63ac71e2fe48c07bb301f2d54187044d
| Author: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
| Date:   Thu Feb 13 13:34:41 2025 +0000
|
|     android-ndk: dont set LD and AS variables (#26581)
|
|     * android-ndk: dont set LD and AS variables
|
|     * android-ndk: refactor test package
|
* commit 123e382fafd2f5e811e10faac02efc275c45ec2a
| Author: Nikita <root.kidik@gmail.com>
| Date:   Thu Feb 13 12:29:39 2025 +0300
|
|     libffi: fix conditionals when building on Windows (#26500)
|
|     * fix: add missing or `clang`
|
|     * fix: libffi - always require as tool `automake`
```
2025-02-19 10:35:08 -08:00
Thomas E Lackey
71e4c273e8
Merge branch 'main' into telackey/sort 2025-02-18 10:54:10 -06:00
Thomas E Lackey
b1c413fe2a
Merge branch 'main' into telackey/sort 2025-02-17 22:40:00 -06:00
Thomas E Lackey
f4d8bfb75e
Merge branch 'main' into telackey/sort 2025-02-17 16:49:12 -06:00
Thomas E Lackey
f3d2f67c28 Migration 2025-02-17 15:18:28 -06:00
Thomas E Lackey
fe195e258a
Merge branch 'main' into telackey/sort 2025-02-17 14:11:28 -06:00
Thomas E Lackey
591acd4300 Lint 2025-02-17 14:07:19 -06:00
Thomas E Lackey
d1586e5ba9 Lint 2025-02-17 13:49:50 -06:00
Thomas E Lackey
de58736eae Tabs not spaces 2025-02-17 13:48:47 -06:00
Thomas E Lackey
6feba525f1
Merge branch 'go-gitea:main' into telackey/sort 2025-01-14 12:07:14 -06:00
Thomas E Lackey
7b4563c88b refactor 2025-01-10 15:22:38 -06:00
Thomas E Lackey
4e89634bd8 sirt 2025-01-10 15:02:29 -06:00
Thomas E Lackey
041b352f5c fmt 2025-01-10 14:49:38 -06:00
Thomas E Lackey
2fa535df84 fmt 2025-01-10 14:48:49 -06:00
Thomas E Lackey
182aed4bfb yaml support 2025-01-10 14:33:49 -06:00
Thomas E Lackey
104e4c517b Adjust format 2025-01-10 13:47:52 -06:00
Thomas E Lackey
bbf913a13e Add sorting of exlusive labels. 2025-01-10 13:43:30 -06:00
19 changed files with 123 additions and 18 deletions

View File

@ -70,6 +70,15 @@ func (o *IssuesOptions) Copy(edit ...func(options *IssuesOptions)) *IssuesOption
// applySorts sort an issues-related session based on the provided
// sortType string
func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {
// Since this sortType is dynamically created, it has to be treated specially.
if strings.HasPrefix(sortType, "scope-") {
scope := strings.TrimPrefix(sortType, "scope-")
sess.Join("LEFT", "issue_label", "issue.id = issue_label.issue_id")
sess.Join("LEFT", "label", "label.id = issue_label.label_id and label.name LIKE ?", scope+"/%")
sess.Asc("label.exclusive_order").Desc("issue.id")
return // EARLY RETURN
}
switch sortType {
case "oldest":
sess.Asc("issue.created_unix").Asc("issue.id")

View File

@ -87,6 +87,7 @@ type Label struct {
OrgID int64 `xorm:"INDEX"`
Name string
Exclusive bool
ExclusiveOrder int `xorm:"DEFAULT 0"`
Description string
Color string `xorm:"VARCHAR(7)"`
NumIssues int
@ -236,7 +237,7 @@ func UpdateLabel(ctx context.Context, l *Label) error {
}
l.Color = color
return updateLabelCols(ctx, l, "name", "description", "color", "exclusive", "archived_unix")
return updateLabelCols(ctx, l, "name", "description", "color", "exclusive", "exclusive_order", "archived_unix")
}
// DeleteLabel delete a label

View File

@ -374,6 +374,7 @@ func prepareMigrationTasks() []*migration {
// Gitea 1.23.0-rc0 ends at migration ID number 311 (database version 312)
newMigration(312, "Add DeleteBranchAfterMerge to AutoMerge", v1_24.AddDeleteBranchAfterMergeForAutoMerge),
newMigration(313, "Move PinOrder from issue table to a new table issue_pin", v1_24.MovePinOrderToTableIssuePin),
newMigration(314, "Add ExclusiveOrder to Label table", v1_24.AddExclusiveOrderColumnToLabelTable),
}
return preparedMigrations
}

View File

@ -0,0 +1,16 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_24 //nolint
import (
"xorm.io/xorm"
)
func AddExclusiveOrderColumnToLabelTable(x *xorm.Engine) error {
type Label struct {
ExclusiveOrder int64 `xorm:"DEFAULT 0"`
}
return x.Sync(new(Label))
}

View File

@ -6,6 +6,7 @@ package db
import (
"context"
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
issue_model "code.gitea.io/gitea/models/issues"
@ -34,7 +35,11 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
case internal.SortByDeadlineAsc:
sortType = "nearduedate"
default:
sortType = "newest"
if strings.HasPrefix(string(options.SortBy), "scope-") {
sortType = string(options.SortBy)
} else {
sortType = "newest"
}
}
// See the comment of issues_model.SearchOptions for the reason why we need to convert

View File

@ -4,8 +4,11 @@
package issues
import (
"strings"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/indexer/issues/internal"
"code.gitea.io/gitea/modules/optional"
)
@ -99,7 +102,11 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
// Unsupported sort type for search
fallthrough
default:
searchOpt.SortBy = SortByUpdatedDesc
if strings.HasPrefix(opts.SortType, "scope-") {
searchOpt.SortBy = internal.SortBy(opts.SortType)
} else {
searchOpt.SortBy = SortByUpdatedDesc
}
}
return searchOpt

View File

@ -14,10 +14,11 @@ var colorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")
// Label represents label information loaded from template
type Label struct {
Name string `yaml:"name"`
Color string `yaml:"color"`
Description string `yaml:"description,omitempty"`
Exclusive bool `yaml:"exclusive,omitempty"`
Name string `yaml:"name"`
Color string `yaml:"color"`
Description string `yaml:"description,omitempty"`
Exclusive bool `yaml:"exclusive,omitempty"`
ExclusiveOrder int `yaml:"exclusive_order,omitempty"`
}
// NormalizeColor normalizes a color string to a 6-character hex code

View File

@ -154,10 +154,11 @@ func InitializeLabels(ctx context.Context, id int64, labelTemplate string, isOrg
labels := make([]*issues_model.Label, len(list))
for i := 0; i < len(list); i++ {
labels[i] = &issues_model.Label{
Name: list[i].Name,
Exclusive: list[i].Exclusive,
Description: list[i].Description,
Color: list[i].Color,
Name: list[i].Name,
Exclusive: list[i].Exclusive,
ExclusiveOrder: list[i].ExclusiveOrder,
Description: list[i].Description,
Color: list[i].Color,
}
if isOrg {
labels[i].OrgID = id

View File

@ -22,49 +22,60 @@ labels:
description: Breaking change that won't be backward compatible
- name: "Reviewed/Duplicate"
exclusive: true
exclusive_order: 50
color: 616161
description: This issue or pull request already exists
- name: "Reviewed/Invalid"
exclusive: true
exclusive_order: 100
color: 546e7a
description: Invalid issue
- name: "Reviewed/Confirmed"
exclusive: true
exclusive_order: 0
color: 795548
description: Issue has been confirmed
- name: "Reviewed/Won't Fix"
exclusive: true
exclusive_order: 75
color: eeeeee
description: This issue won't be fixed
- name: "Status/Need More Info"
exclusive: true
exclusive_order: 25
color: 424242
description: Feedback is required to reproduce issue or to continue work
- name: "Status/Blocked"
exclusive: true
exclusive_order: 0
color: 880e4f
description: Something is blocking this issue or pull request
- name: "Status/Abandoned"
exclusive: true
exclusive_order: 100
color: "222222"
description: Somebody has started to work on this but abandoned work
- name: "Priority/Critical"
exclusive: true
exclusive_order: 0
color: b71c1c
description: The priority is critical
priority: critical
- name: "Priority/High"
exclusive: true
exclusive_order: 1
color: d32f2f
description: The priority is high
priority: high
- name: "Priority/Medium"
exclusive: true
exclusive_order: 2
color: e64a19
description: The priority is medium
priority: medium
- name: "Priority/Low"
exclusive: true
exclusive_order: 3
color: 4caf50
description: The priority is low
priority: low

View File

@ -1644,6 +1644,8 @@ issues.label_archived_filter = Show archived labels
issues.label_archive_tooltip = Archived labels are excluded by default from the suggestions when searching by label.
issues.label_exclusive_desc = Name the label <code>scope/item</code> to make it mutually exclusive with other <code>scope/</code> labels.
issues.label_exclusive_warning = Any conflicting scoped labels will be removed when editing the labels of an issue or pull request.
issues.label_exclusive_order = Sort Order
issues.label_exclusive_order_tooltip = Exclusive labels in the same scope will be sorted according to this numeric order.
issues.label_count = %d labels
issues.label_open_issues = %d open issues/pull requests
issues.label_edit = Edit

View File

@ -1701,7 +1701,9 @@ issues.time_estimate_invalid=O formato da estimativa de tempo é inválido
issues.start_tracking_history=começou a trabalhar %s
issues.tracker_auto_close=O cronómetro será parado automaticamente quando esta questão for fechada
issues.tracking_already_started=`Você já iniciou a contagem de tempo <a href="%s">noutra questão</a>!`
issues.stop_tracking=Parar cronómetro
issues.stop_tracking_history=trabalhou durante <b>%[1]s</b> %[2]s
issues.cancel_tracking=Descartar
issues.cancel_tracking_history=`cancelou a contagem de tempo %s`
issues.del_time=Eliminar este registo de tempo
issues.add_time_history=adicionou <b>%[1]s</b> de tempo gasto %[2]s

View File

@ -139,6 +139,7 @@ func UpdateLabel(ctx *context.Context) {
}
l.Name = form.Title
l.Exclusive = form.Exclusive
l.ExclusiveOrder = form.ExclusiveOrder
l.Description = form.Description
l.Color = form.Color

View File

@ -6,7 +6,10 @@ package repo
import (
"bytes"
"fmt"
"maps"
"net/http"
"slices"
"sort"
"strconv"
"strings"
@ -459,6 +462,25 @@ func UpdateIssueStatus(ctx *context.Context) {
ctx.JSONOK()
}
func renderExclusiveLabelScopes(ctx *context.Context) {
labels, err := issues_model.GetLabelsByRepoID(ctx, ctx.Repo.Repository.ID, "", db.ListOptions{})
if err != nil {
ctx.ServerError("GetAllRepoLabels", err)
return
}
scopeSet := make(map[string]bool, 0)
for _, label := range labels {
scope := label.ExclusiveScope()
if len(scope) > 0 {
scopeSet[scope] = true
}
}
scopes := slices.Collect(maps.Keys(scopeSet))
sort.Strings(scopes)
ctx.Data["ExclusiveLabelScopes"] = scopes
}
func renderMilestones(ctx *context.Context) {
// Get milestones
milestones, err := db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
@ -778,6 +800,11 @@ func Issues(ctx *context.Context) {
return
}
renderExclusiveLabelScopes(ctx)
if ctx.Written() {
return
}
ctx.Data["CanWriteIssuesOrPulls"] = ctx.Repo.CanWriteIssuesOrPulls(isPullList)
ctx.HTML(http.StatusOK, tplIssues)

View File

@ -528,12 +528,13 @@ func (f *CreateMilestoneForm) Validate(req *http.Request, errs binding.Errors) b
// CreateLabelForm form for creating label
type CreateLabelForm struct {
ID int64
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_title"`
Exclusive bool `form:"exclusive"`
IsArchived bool `form:"is_archived"`
Description string `binding:"MaxSize(200)" locale:"repo.issues.label_description"`
Color string `binding:"Required;MaxSize(7)" locale:"repo.issues.label_color"`
ID int64
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_title"`
Exclusive bool `form:"exclusive"`
ExclusiveOrder int `form:"exclusive_order"`
IsArchived bool `form:"is_archived"`
Description string `binding:"MaxSize(200)" locale:"repo.issues.label_description"`
Color string `binding:"Required;MaxSize(7)" locale:"repo.issues.label_color"`
}
// Validate validates the fields

View File

@ -29,7 +29,7 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
}
if len(branches) == 0 {
graphCmd.AddArguments("--all")
graphCmd.AddArguments("--tags", "--branches")
}
graphCmd.AddArguments("-C", "-M", "--date=iso-strict").

View File

@ -133,5 +133,12 @@
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "leastcomment"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "nearduedate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "farduedate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
<div class="divider"></div>
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_label"}}</div>
{{range .ExclusiveLabelScopes}}
{{$scope := .}}
{{$sortType := (printf "scope-%s" $scope)}}
<a class="{{if eq $.SortType $sortType}}active {{end}}item" href="{{QueryBuild $queryLink "sort" $sortType}}">{{$scope}}</a>
{{end}}
</div>
</div>

View File

@ -25,6 +25,14 @@
{{svg "octicon-alert"}} {{ctx.Locale.Tr "repo.issues.label_exclusive_warning"}}
</div>
<br>
<div class="field label-exclusive-order-input-field" style="margin-top: 0.5em">
<label for="exclusive_order">{{ctx.Locale.Tr "repo.issues.label_exclusive_order"}}
<i class="tw-ml-1" data-tooltip-content={{ctx.Locale.Tr "repo.issues.label_exclusive_order_tooltip"}}>
{{svg "octicon-info"}}
</i>
</label>
<input class="label-exclusive-order-input" name="exclusive_order" type="number" maxlength="4">
</div>
</div>
<div class="field label-is-archived-input-field">
<div class="ui checkbox">

View File

@ -50,6 +50,7 @@
data-label-id="{{.ID}}" data-label-name="{{.Name}}" data-label-color="{{.Color}}"
data-label-exclusive="{{.Exclusive}}" data-label-is-archived="{{gt .ArchivedUnix 0}}"
data-label-num-issues="{{.NumIssues}}" data-label-description="{{.Description}}"
data-label-exclusive-order="{{.ExclusiveOrder}}"
>{{svg "octicon-pencil"}} {{ctx.Locale.Tr "repo.issues.label_edit"}}</a>
<a class="link-action" href="#" data-url="{{$.Link}}/delete?id={{.ID}}"
data-modal-confirm-header="{{ctx.Locale.Tr "repo.issues.label_deletion"}}"

View File

@ -18,6 +18,8 @@ export function initCompLabelEdit(pageSelector: string) {
const elExclusiveField = elModal.querySelector('.label-exclusive-input-field');
const elExclusiveInput = elModal.querySelector<HTMLInputElement>('.label-exclusive-input');
const elExclusiveWarning = elModal.querySelector('.label-exclusive-warning');
const elExclusiveOrderField = elModal.querySelector<HTMLInputElement>('.label-exclusive-order-input-field');
const elExclusiveOrderInput = elModal.querySelector<HTMLInputElement>('.label-exclusive-order-input');
const elIsArchivedField = elModal.querySelector('.label-is-archived-input-field');
const elIsArchivedInput = elModal.querySelector<HTMLInputElement>('.label-is-archived-input');
const elDescInput = elModal.querySelector<HTMLInputElement>('.label-desc-input');
@ -29,6 +31,7 @@ export function initCompLabelEdit(pageSelector: string) {
const showExclusiveWarning = hasScope && elExclusiveInput.checked && elModal.hasAttribute('data-need-warn-exclusive');
toggleElem(elExclusiveWarning, showExclusiveWarning);
if (!hasScope) elExclusiveInput.checked = false;
toggleElem(elExclusiveOrderField, elExclusiveInput.checked);
};
const showLabelEditModal = (btn:HTMLElement) => {
@ -36,6 +39,7 @@ export function initCompLabelEdit(pageSelector: string) {
const form = elModal.querySelector<HTMLFormElement>('form');
elLabelId.value = btn.getAttribute('data-label-id') || '';
elNameInput.value = btn.getAttribute('data-label-name') || '';
elExclusiveOrderInput.value = btn.getAttribute('data-label-exclusive-order') || '0';
elIsArchivedInput.checked = btn.getAttribute('data-label-is-archived') === 'true';
elExclusiveInput.checked = btn.getAttribute('data-label-exclusive') === 'true';
elDescInput.value = btn.getAttribute('data-label-description') || '';