Skip to content

Commit 0787041

Browse files
authored
Merge branch 'main' into fix-install-bug
2 parents 7dcc0a1 + 2f49b55 commit 0787041

File tree

112 files changed

+1822
-692
lines changed

Some content is hidden

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

112 files changed

+1822
-692
lines changed

build/update-locales.sh

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,49 @@
1-
#!/bin/sh
1+
#!/bin/bash
2+
3+
set -e
4+
5+
SED=sed
6+
7+
if [[ $OSTYPE == 'darwin'* ]]; then
8+
# for macOS developers, use "brew install gnu-sed"
9+
SED=gsed
10+
fi
11+
12+
if [ ! -f ./options/locale/locale_en-US.ini ]; then
13+
echo "please run this script in the root directory of the project"
14+
exit 1
15+
fi
216

317
mv ./options/locale/locale_en-US.ini ./options/
418

5-
# Make sure to only change lines that have the translation enclosed between quotes
6-
sed -i -r -e '/^[a-zA-Z0-9_.-]+[ ]*=[ ]*".*"$/ {
7-
s/^([a-zA-Z0-9_.-]+)[ ]*="/\1=/
8-
s/\\"/"/g
19+
# the "ini" library for locale has many quirks
20+
# * `a="xx"` gets `xx` (no quote)
21+
# * `a=x\"y` gets `x\"y` (no unescaping)
22+
# * `a="x\"y"` gets `"x\"y"` (no unescaping, the quotes are still there)
23+
# * `a='x\"y'` gets `x\"y` (no unescaping, no quote)
24+
# * `a="foo` gets `"foo` (although the quote is not closed)
25+
# * 'a=`foo`' works like single-quote
26+
# crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes
27+
# crowdin always outputs quoted strings if there are quotes in the strings.
28+
29+
# this script helps to unquote the crowdin outputs for the quirky ini library
30+
# * find all `key="...\"..."` lines
31+
# * remove the leading quote
32+
# * remove the trailing quote
33+
# * unescape the quotes
34+
# * eg: key="...\"..." => key=..."...
35+
$SED -i -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
36+
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
937
s/"$//
38+
s/\\"/"/g
1039
}' ./options/locale/*.ini
1140

41+
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
42+
# * eg: key="... => key=`"...`
43+
# * eg: key=..." => key=`..."`
44+
$SED -i -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
45+
$SED -i -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
46+
1247
# Remove translation under 25% of en_us
1348
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
1449
baselines=$((baselines / 4))

cmd/dump.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ func runDump(ctx *cli.Context) error {
272272
fatal("Failed to create tmp file: %v", err)
273273
}
274274
defer func() {
275+
_ = dbDump.Close()
275276
if err := util.Remove(dbDump.Name()); err != nil {
276277
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
277278
}

cmd/serv.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"net/url"
1212
"os"
1313
"os/exec"
14+
"path/filepath"
1415
"regexp"
1516
"strconv"
1617
"strings"
@@ -290,17 +291,21 @@ func runServ(c *cli.Context) error {
290291
return nil
291292
}
292293

293-
// Special handle for Windows.
294-
if setting.IsWindows {
295-
verb = strings.Replace(verb, "-", " ", 1)
296-
}
297-
298294
var gitcmd *exec.Cmd
299-
verbs := strings.Split(verb, " ")
300-
if len(verbs) == 2 {
301-
gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath)
302-
} else {
303-
gitcmd = exec.CommandContext(ctx, verb, repoPath)
295+
gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin
296+
gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
297+
if _, err := os.Stat(gitBinVerb); err != nil {
298+
// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
299+
// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
300+
verbFields := strings.SplitN(verb, "-", 2)
301+
if len(verbFields) == 2 {
302+
// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
303+
gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath)
304+
}
305+
}
306+
if gitcmd == nil {
307+
// by default, use the verb (it has been checked above by allowedCommands)
308+
gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath)
304309
}
305310

306311
process.SetSysProcAttribute(gitcmd)

docs/content/doc/developers/guidelines-frontend.en-us.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ It's not recommended to use `async` event listeners, which may lead to problems.
8383
The reason is that the code after await is executed outside the event dispatch.
8484
Reference: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md
8585

86+
If an event listener must be `async`, the `e.preventDefault()` should be before any `await`,
87+
it's recommended to put it at the beginning of the function.
88+
8689
If we want to call an `async` function in a non-async context,
8790
it's recommended to use `const _promise = asyncFoo()` to tell readers
8891
that this is done by purpose, we want to call the async function and ignore the Promise.

models/fixtures/repository.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
fork_id: 0
2626
is_template: false
2727
template_id: 0
28-
size: 6708
28+
size: 7028
2929
is_fsck_enabled: true
3030
close_issues_via_commit_in_any_branch: false
3131

models/issues/label.go

Lines changed: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ package issues
77
import (
88
"context"
99
"fmt"
10-
"regexp"
1110
"strconv"
1211
"strings"
1312

1413
"code.gitea.io/gitea/models/db"
1514
user_model "code.gitea.io/gitea/models/user"
15+
"code.gitea.io/gitea/modules/label"
1616
"code.gitea.io/gitea/modules/timeutil"
1717
"code.gitea.io/gitea/modules/util"
1818

@@ -78,9 +78,6 @@ func (err ErrLabelNotExist) Unwrap() error {
7878
return util.ErrNotExist
7979
}
8080

81-
// LabelColorPattern is a regexp witch can validate LabelColor
82-
var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")
83-
8481
// Label represents a label of repository for issues.
8582
type Label struct {
8683
ID int64 `xorm:"pk autoincr"`
@@ -109,35 +106,35 @@ func init() {
109106
}
110107

111108
// CalOpenIssues sets the number of open issues of a label based on the already stored number of closed issues.
112-
func (label *Label) CalOpenIssues() {
113-
label.NumOpenIssues = label.NumIssues - label.NumClosedIssues
109+
func (l *Label) CalOpenIssues() {
110+
l.NumOpenIssues = l.NumIssues - l.NumClosedIssues
114111
}
115112

116113
// CalOpenOrgIssues calculates the open issues of a label for a specific repo
117-
func (label *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
114+
func (l *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
118115
counts, _ := CountIssuesByRepo(ctx, &IssuesOptions{
119116
RepoID: repoID,
120117
LabelIDs: []int64{labelID},
121118
IsClosed: util.OptionalBoolFalse,
122119
})
123120

124121
for _, count := range counts {
125-
label.NumOpenRepoIssues += count
122+
l.NumOpenRepoIssues += count
126123
}
127124
}
128125

129126
// LoadSelectedLabelsAfterClick calculates the set of selected labels when a label is clicked
130-
func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64, currentSelectedExclusiveScopes []string) {
127+
func (l *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64, currentSelectedExclusiveScopes []string) {
131128
var labelQuerySlice []string
132129
labelSelected := false
133-
labelID := strconv.FormatInt(label.ID, 10)
134-
labelScope := label.ExclusiveScope()
130+
labelID := strconv.FormatInt(l.ID, 10)
131+
labelScope := l.ExclusiveScope()
135132
for i, s := range currentSelectedLabels {
136-
if s == label.ID {
133+
if s == l.ID {
137134
labelSelected = true
138-
} else if -s == label.ID {
135+
} else if -s == l.ID {
139136
labelSelected = true
140-
label.IsExcluded = true
137+
l.IsExcluded = true
141138
} else if s != 0 {
142139
// Exclude other labels in the same scope from selection
143140
if s < 0 || labelScope == "" || labelScope != currentSelectedExclusiveScopes[i] {
@@ -148,23 +145,23 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64,
148145
if !labelSelected {
149146
labelQuerySlice = append(labelQuerySlice, labelID)
150147
}
151-
label.IsSelected = labelSelected
152-
label.QueryString = strings.Join(labelQuerySlice, ",")
148+
l.IsSelected = labelSelected
149+
l.QueryString = strings.Join(labelQuerySlice, ",")
153150
}
154151

155152
// BelongsToOrg returns true if label is an organization label
156-
func (label *Label) BelongsToOrg() bool {
157-
return label.OrgID > 0
153+
func (l *Label) BelongsToOrg() bool {
154+
return l.OrgID > 0
158155
}
159156

160157
// BelongsToRepo returns true if label is a repository label
161-
func (label *Label) BelongsToRepo() bool {
162-
return label.RepoID > 0
158+
func (l *Label) BelongsToRepo() bool {
159+
return l.RepoID > 0
163160
}
164161

165162
// Get color as RGB values in 0..255 range
166-
func (label *Label) ColorRGB() (float64, float64, float64, error) {
167-
color, err := strconv.ParseUint(label.Color[1:], 16, 64)
163+
func (l *Label) ColorRGB() (float64, float64, float64, error) {
164+
color, err := strconv.ParseUint(l.Color[1:], 16, 64)
168165
if err != nil {
169166
return 0, 0, 0, err
170167
}
@@ -176,9 +173,9 @@ func (label *Label) ColorRGB() (float64, float64, float64, error) {
176173
}
177174

178175
// Determine if label text should be light or dark to be readable on background color
179-
func (label *Label) UseLightTextColor() bool {
180-
if strings.HasPrefix(label.Color, "#") {
181-
if r, g, b, err := label.ColorRGB(); err == nil {
176+
func (l *Label) UseLightTextColor() bool {
177+
if strings.HasPrefix(l.Color, "#") {
178+
if r, g, b, err := l.ColorRGB(); err == nil {
182179
// Perceived brightness from: https://www.w3.org/TR/AERT/#color-contrast
183180
// In the future WCAG 3 APCA may be a better solution
184181
brightness := (0.299*r + 0.587*g + 0.114*b) / 255
@@ -190,40 +187,26 @@ func (label *Label) UseLightTextColor() bool {
190187
}
191188

192189
// Return scope substring of label name, or empty string if none exists
193-
func (label *Label) ExclusiveScope() string {
194-
if !label.Exclusive {
190+
func (l *Label) ExclusiveScope() string {
191+
if !l.Exclusive {
195192
return ""
196193
}
197-
lastIndex := strings.LastIndex(label.Name, "/")
198-
if lastIndex == -1 || lastIndex == 0 || lastIndex == len(label.Name)-1 {
194+
lastIndex := strings.LastIndex(l.Name, "/")
195+
if lastIndex == -1 || lastIndex == 0 || lastIndex == len(l.Name)-1 {
199196
return ""
200197
}
201-
return label.Name[:lastIndex]
198+
return l.Name[:lastIndex]
202199
}
203200

204201
// NewLabel creates a new label
205-
func NewLabel(ctx context.Context, label *Label) error {
206-
if !LabelColorPattern.MatchString(label.Color) {
207-
return fmt.Errorf("bad color code: %s", label.Color)
208-
}
209-
210-
// normalize case
211-
label.Color = strings.ToLower(label.Color)
212-
213-
// add leading hash
214-
if label.Color[0] != '#' {
215-
label.Color = "#" + label.Color
216-
}
217-
218-
// convert 3-character shorthand into 6-character version
219-
if len(label.Color) == 4 {
220-
r := label.Color[1]
221-
g := label.Color[2]
222-
b := label.Color[3]
223-
label.Color = fmt.Sprintf("#%c%c%c%c%c%c", r, r, g, g, b, b)
202+
func NewLabel(ctx context.Context, l *Label) error {
203+
color, err := label.NormalizeColor(l.Color)
204+
if err != nil {
205+
return err
224206
}
207+
l.Color = color
225208

226-
return db.Insert(ctx, label)
209+
return db.Insert(ctx, l)
227210
}
228211

229212
// NewLabels creates new labels
@@ -234,11 +217,14 @@ func NewLabels(labels ...*Label) error {
234217
}
235218
defer committer.Close()
236219

237-
for _, label := range labels {
238-
if !LabelColorPattern.MatchString(label.Color) {
239-
return fmt.Errorf("bad color code: %s", label.Color)
220+
for _, l := range labels {
221+
color, err := label.NormalizeColor(l.Color)
222+
if err != nil {
223+
return err
240224
}
241-
if err := db.Insert(ctx, label); err != nil {
225+
l.Color = color
226+
227+
if err := db.Insert(ctx, l); err != nil {
242228
return err
243229
}
244230
}
@@ -247,15 +233,18 @@ func NewLabels(labels ...*Label) error {
247233

248234
// UpdateLabel updates label information.
249235
func UpdateLabel(l *Label) error {
250-
if !LabelColorPattern.MatchString(l.Color) {
251-
return fmt.Errorf("bad color code: %s", l.Color)
236+
color, err := label.NormalizeColor(l.Color)
237+
if err != nil {
238+
return err
252239
}
240+
l.Color = color
241+
253242
return updateLabelCols(db.DefaultContext, l, "name", "description", "color", "exclusive")
254243
}
255244

256245
// DeleteLabel delete a label
257246
func DeleteLabel(id, labelID int64) error {
258-
label, err := GetLabelByID(db.DefaultContext, labelID)
247+
l, err := GetLabelByID(db.DefaultContext, labelID)
259248
if err != nil {
260249
if IsErrLabelNotExist(err) {
261250
return nil
@@ -271,10 +260,10 @@ func DeleteLabel(id, labelID int64) error {
271260

272261
sess := db.GetEngine(ctx)
273262

274-
if label.BelongsToOrg() && label.OrgID != id {
263+
if l.BelongsToOrg() && l.OrgID != id {
275264
return nil
276265
}
277-
if label.BelongsToRepo() && label.RepoID != id {
266+
if l.BelongsToRepo() && l.RepoID != id {
278267
return nil
279268
}
280269

@@ -682,14 +671,14 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
682671
if err = issue.LoadRepo(ctx); err != nil {
683672
return err
684673
}
685-
for _, label := range labels {
674+
for _, l := range labels {
686675
// Don't add already present labels and invalid labels
687-
if HasIssueLabel(ctx, issue.ID, label.ID) ||
688-
(label.RepoID != issue.RepoID && label.OrgID != issue.Repo.OwnerID) {
676+
if HasIssueLabel(ctx, issue.ID, l.ID) ||
677+
(l.RepoID != issue.RepoID && l.OrgID != issue.Repo.OwnerID) {
689678
continue
690679
}
691680

692-
if err = newIssueLabel(ctx, issue, label, doer); err != nil {
681+
if err = newIssueLabel(ctx, issue, l, doer); err != nil {
693682
return fmt.Errorf("newIssueLabel: %w", err)
694683
}
695684
}

models/issues/label_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import (
1515
"github.com/stretchr/testify/assert"
1616
)
1717

18-
// TODO TestGetLabelTemplateFile
19-
2018
func TestLabel_CalOpenIssues(t *testing.T) {
2119
assert.NoError(t, unittest.PrepareTestDatabase())
2220
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})

0 commit comments

Comments
 (0)