Skip to content

Commit

Permalink
Merge branch 'main' into fix-install-bug
Browse files Browse the repository at this point in the history
  • Loading branch information
lunny authored Mar 3, 2023
2 parents 7dcc0a1 + 2f49b55 commit 0787041
Show file tree
Hide file tree
Showing 112 changed files with 1,822 additions and 692 deletions.
45 changes: 40 additions & 5 deletions build/update-locales.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
#!/bin/sh
#!/bin/bash

set -e

SED=sed

if [[ $OSTYPE == 'darwin'* ]]; then
# for macOS developers, use "brew install gnu-sed"
SED=gsed
fi

if [ ! -f ./options/locale/locale_en-US.ini ]; then
echo "please run this script in the root directory of the project"
exit 1
fi

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

# Make sure to only change lines that have the translation enclosed between quotes
sed -i -r -e '/^[a-zA-Z0-9_.-]+[ ]*=[ ]*".*"$/ {
s/^([a-zA-Z0-9_.-]+)[ ]*="/\1=/
s/\\"/"/g
# the "ini" library for locale has many quirks
# * `a="xx"` gets `xx` (no quote)
# * `a=x\"y` gets `x\"y` (no unescaping)
# * `a="x\"y"` gets `"x\"y"` (no unescaping, the quotes are still there)
# * `a='x\"y'` gets `x\"y` (no unescaping, no quote)
# * `a="foo` gets `"foo` (although the quote is not closed)
# * 'a=`foo`' works like single-quote
# crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes
# crowdin always outputs quoted strings if there are quotes in the strings.

# this script helps to unquote the crowdin outputs for the quirky ini library
# * find all `key="...\"..."` lines
# * remove the leading quote
# * remove the trailing quote
# * unescape the quotes
# * eg: key="...\"..." => key=..."...
$SED -i -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
s/"$//
s/\\"/"/g
}' ./options/locale/*.ini

# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
# * eg: key="... => key=`"...`
# * eg: key=..." => key=`..."`
$SED -i -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
$SED -i -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini

# Remove translation under 25% of en_us
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
baselines=$((baselines / 4))
Expand Down
1 change: 1 addition & 0 deletions cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ func runDump(ctx *cli.Context) error {
fatal("Failed to create tmp file: %v", err)
}
defer func() {
_ = dbDump.Close()
if err := util.Remove(dbDump.Name()); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
}
Expand Down
25 changes: 15 additions & 10 deletions cmd/serv.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -290,17 +291,21 @@ func runServ(c *cli.Context) error {
return nil
}

// Special handle for Windows.
if setting.IsWindows {
verb = strings.Replace(verb, "-", " ", 1)
}

var gitcmd *exec.Cmd
verbs := strings.Split(verb, " ")
if len(verbs) == 2 {
gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath)
} else {
gitcmd = exec.CommandContext(ctx, verb, repoPath)
gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin
gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
if _, err := os.Stat(gitBinVerb); err != nil {
// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
verbFields := strings.SplitN(verb, "-", 2)
if len(verbFields) == 2 {
// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath)
}
}
if gitcmd == nil {
// by default, use the verb (it has been checked above by allowedCommands)
gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath)
}

process.SetSysProcAttribute(gitcmd)
Expand Down
3 changes: 3 additions & 0 deletions docs/content/doc/developers/guidelines-frontend.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ It's not recommended to use `async` event listeners, which may lead to problems.
The reason is that the code after await is executed outside the event dispatch.
Reference: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md

If an event listener must be `async`, the `e.preventDefault()` should be before any `await`,
it's recommended to put it at the beginning of the function.

If we want to call an `async` function in a non-async context,
it's recommended to use `const _promise = asyncFoo()` to tell readers
that this is done by purpose, we want to call the async function and ignore the Promise.
Expand Down
2 changes: 1 addition & 1 deletion models/fixtures/repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
fork_id: 0
is_template: false
template_id: 0
size: 6708
size: 7028
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false

Expand Down
115 changes: 52 additions & 63 deletions models/issues/label.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ package issues
import (
"context"
"fmt"
"regexp"
"strconv"
"strings"

"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/label"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

Expand Down Expand Up @@ -78,9 +78,6 @@ func (err ErrLabelNotExist) Unwrap() error {
return util.ErrNotExist
}

// LabelColorPattern is a regexp witch can validate LabelColor
var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")

// Label represents a label of repository for issues.
type Label struct {
ID int64 `xorm:"pk autoincr"`
Expand Down Expand Up @@ -109,35 +106,35 @@ func init() {
}

// CalOpenIssues sets the number of open issues of a label based on the already stored number of closed issues.
func (label *Label) CalOpenIssues() {
label.NumOpenIssues = label.NumIssues - label.NumClosedIssues
func (l *Label) CalOpenIssues() {
l.NumOpenIssues = l.NumIssues - l.NumClosedIssues
}

// CalOpenOrgIssues calculates the open issues of a label for a specific repo
func (label *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
func (l *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
counts, _ := CountIssuesByRepo(ctx, &IssuesOptions{
RepoID: repoID,
LabelIDs: []int64{labelID},
IsClosed: util.OptionalBoolFalse,
})

for _, count := range counts {
label.NumOpenRepoIssues += count
l.NumOpenRepoIssues += count
}
}

// LoadSelectedLabelsAfterClick calculates the set of selected labels when a label is clicked
func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64, currentSelectedExclusiveScopes []string) {
func (l *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64, currentSelectedExclusiveScopes []string) {
var labelQuerySlice []string
labelSelected := false
labelID := strconv.FormatInt(label.ID, 10)
labelScope := label.ExclusiveScope()
labelID := strconv.FormatInt(l.ID, 10)
labelScope := l.ExclusiveScope()
for i, s := range currentSelectedLabels {
if s == label.ID {
if s == l.ID {
labelSelected = true
} else if -s == label.ID {
} else if -s == l.ID {
labelSelected = true
label.IsExcluded = true
l.IsExcluded = true
} else if s != 0 {
// Exclude other labels in the same scope from selection
if s < 0 || labelScope == "" || labelScope != currentSelectedExclusiveScopes[i] {
Expand All @@ -148,23 +145,23 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64,
if !labelSelected {
labelQuerySlice = append(labelQuerySlice, labelID)
}
label.IsSelected = labelSelected
label.QueryString = strings.Join(labelQuerySlice, ",")
l.IsSelected = labelSelected
l.QueryString = strings.Join(labelQuerySlice, ",")
}

// BelongsToOrg returns true if label is an organization label
func (label *Label) BelongsToOrg() bool {
return label.OrgID > 0
func (l *Label) BelongsToOrg() bool {
return l.OrgID > 0
}

// BelongsToRepo returns true if label is a repository label
func (label *Label) BelongsToRepo() bool {
return label.RepoID > 0
func (l *Label) BelongsToRepo() bool {
return l.RepoID > 0
}

// Get color as RGB values in 0..255 range
func (label *Label) ColorRGB() (float64, float64, float64, error) {
color, err := strconv.ParseUint(label.Color[1:], 16, 64)
func (l *Label) ColorRGB() (float64, float64, float64, error) {
color, err := strconv.ParseUint(l.Color[1:], 16, 64)
if err != nil {
return 0, 0, 0, err
}
Expand All @@ -176,9 +173,9 @@ func (label *Label) ColorRGB() (float64, float64, float64, error) {
}

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

// Return scope substring of label name, or empty string if none exists
func (label *Label) ExclusiveScope() string {
if !label.Exclusive {
func (l *Label) ExclusiveScope() string {
if !l.Exclusive {
return ""
}
lastIndex := strings.LastIndex(label.Name, "/")
if lastIndex == -1 || lastIndex == 0 || lastIndex == len(label.Name)-1 {
lastIndex := strings.LastIndex(l.Name, "/")
if lastIndex == -1 || lastIndex == 0 || lastIndex == len(l.Name)-1 {
return ""
}
return label.Name[:lastIndex]
return l.Name[:lastIndex]
}

// NewLabel creates a new label
func NewLabel(ctx context.Context, label *Label) error {
if !LabelColorPattern.MatchString(label.Color) {
return fmt.Errorf("bad color code: %s", label.Color)
}

// normalize case
label.Color = strings.ToLower(label.Color)

// add leading hash
if label.Color[0] != '#' {
label.Color = "#" + label.Color
}

// convert 3-character shorthand into 6-character version
if len(label.Color) == 4 {
r := label.Color[1]
g := label.Color[2]
b := label.Color[3]
label.Color = fmt.Sprintf("#%c%c%c%c%c%c", r, r, g, g, b, b)
func NewLabel(ctx context.Context, l *Label) error {
color, err := label.NormalizeColor(l.Color)
if err != nil {
return err
}
l.Color = color

return db.Insert(ctx, label)
return db.Insert(ctx, l)
}

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

for _, label := range labels {
if !LabelColorPattern.MatchString(label.Color) {
return fmt.Errorf("bad color code: %s", label.Color)
for _, l := range labels {
color, err := label.NormalizeColor(l.Color)
if err != nil {
return err
}
if err := db.Insert(ctx, label); err != nil {
l.Color = color

if err := db.Insert(ctx, l); err != nil {
return err
}
}
Expand All @@ -247,15 +233,18 @@ func NewLabels(labels ...*Label) error {

// UpdateLabel updates label information.
func UpdateLabel(l *Label) error {
if !LabelColorPattern.MatchString(l.Color) {
return fmt.Errorf("bad color code: %s", l.Color)
color, err := label.NormalizeColor(l.Color)
if err != nil {
return err
}
l.Color = color

return updateLabelCols(db.DefaultContext, l, "name", "description", "color", "exclusive")
}

// DeleteLabel delete a label
func DeleteLabel(id, labelID int64) error {
label, err := GetLabelByID(db.DefaultContext, labelID)
l, err := GetLabelByID(db.DefaultContext, labelID)
if err != nil {
if IsErrLabelNotExist(err) {
return nil
Expand All @@ -271,10 +260,10 @@ func DeleteLabel(id, labelID int64) error {

sess := db.GetEngine(ctx)

if label.BelongsToOrg() && label.OrgID != id {
if l.BelongsToOrg() && l.OrgID != id {
return nil
}
if label.BelongsToRepo() && label.RepoID != id {
if l.BelongsToRepo() && l.RepoID != id {
return nil
}

Expand Down Expand Up @@ -682,14 +671,14 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
if err = issue.LoadRepo(ctx); err != nil {
return err
}
for _, label := range labels {
for _, l := range labels {
// Don't add already present labels and invalid labels
if HasIssueLabel(ctx, issue.ID, label.ID) ||
(label.RepoID != issue.RepoID && label.OrgID != issue.Repo.OwnerID) {
if HasIssueLabel(ctx, issue.ID, l.ID) ||
(l.RepoID != issue.RepoID && l.OrgID != issue.Repo.OwnerID) {
continue
}

if err = newIssueLabel(ctx, issue, label, doer); err != nil {
if err = newIssueLabel(ctx, issue, l, doer); err != nil {
return fmt.Errorf("newIssueLabel: %w", err)
}
}
Expand Down
2 changes: 0 additions & 2 deletions models/issues/label_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (
"github.com/stretchr/testify/assert"
)

// TODO TestGetLabelTemplateFile

func TestLabel_CalOpenIssues(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
Expand Down
Loading

0 comments on commit 0787041

Please sign in to comment.