Fix various bugs (#36139) (#36151)

Backport #36139

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Giteabot
2025-12-13 21:31:49 +08:00
committed by GitHub
parent 432e128074
commit 2dd8ef8368
8 changed files with 80 additions and 37 deletions

View File

@@ -62,7 +62,28 @@ type PackageMetadata struct {
Author User `json:"author"` Author User `json:"author"`
ReadmeFilename string `json:"readmeFilename,omitempty"` ReadmeFilename string `json:"readmeFilename,omitempty"`
Users map[string]bool `json:"users,omitempty"` Users map[string]bool `json:"users,omitempty"`
License string `json:"license,omitempty"` License License `json:"license,omitempty"`
}
type License string
func (l *License) UnmarshalJSON(data []byte) error {
switch data[0] {
case '"':
var value string
if err := json.Unmarshal(data, &value); err != nil {
return err
}
*l = License(value)
case '{':
var values map[string]any
if err := json.Unmarshal(data, &values); err != nil {
return err
}
value, _ := values["type"].(string)
*l = License(value)
}
return nil
} }
// PackageMetadataVersion documentation: https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#version // PackageMetadataVersion documentation: https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#version
@@ -74,7 +95,7 @@ type PackageMetadataVersion struct {
Description string `json:"description"` Description string `json:"description"`
Author User `json:"author"` Author User `json:"author"`
Homepage string `json:"homepage,omitempty"` Homepage string `json:"homepage,omitempty"`
License string `json:"license,omitempty"` License License `json:"license,omitempty"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
Keywords []string `json:"keywords,omitempty"` Keywords []string `json:"keywords,omitempty"`
Dependencies map[string]string `json:"dependencies,omitempty"` Dependencies map[string]string `json:"dependencies,omitempty"`

View File

@@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestParsePackage(t *testing.T) { func TestParsePackage(t *testing.T) {
@@ -291,11 +292,36 @@ func TestParsePackage(t *testing.T) {
assert.Equal(t, packageDescription, p.Metadata.Readme) assert.Equal(t, packageDescription, p.Metadata.Readme)
assert.Equal(t, packageAuthor, p.Metadata.Author) assert.Equal(t, packageAuthor, p.Metadata.Author)
assert.Equal(t, packageBin, p.Metadata.Bin["bin"]) assert.Equal(t, packageBin, p.Metadata.Bin["bin"])
assert.Equal(t, "MIT", p.Metadata.License) assert.Equal(t, "MIT", string(p.Metadata.License))
assert.Equal(t, "https://gitea.io/", p.Metadata.ProjectURL) assert.Equal(t, "https://gitea.io/", p.Metadata.ProjectURL)
assert.Contains(t, p.Metadata.Dependencies, "package") assert.Contains(t, p.Metadata.Dependencies, "package")
assert.Equal(t, "1.2.0", p.Metadata.Dependencies["package"]) assert.Equal(t, "1.2.0", p.Metadata.Dependencies["package"])
assert.Equal(t, repository.Type, p.Metadata.Repository.Type) assert.Equal(t, repository.Type, p.Metadata.Repository.Type)
assert.Equal(t, repository.URL, p.Metadata.Repository.URL) assert.Equal(t, repository.URL, p.Metadata.Repository.URL)
}) })
t.Run("ValidLicenseMap", func(t *testing.T) {
packageJSON := `{
"versions": {
"0.1.1": {
"name": "dev-null",
"version": "0.1.1",
"license": {
"type": "MIT"
},
"dist": {
"integrity": "sha256-"
}
}
},
"_attachments": {
"foo": {
"data": "AAAA"
}
}
}`
p, err := ParsePackage(strings.NewReader(packageJSON))
require.NoError(t, err)
require.Equal(t, "MIT", string(p.Metadata.License))
})
} }

View File

@@ -12,7 +12,7 @@ type Metadata struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
Author string `json:"author,omitempty"` Author string `json:"author,omitempty"`
License string `json:"license,omitempty"` License License `json:"license,omitempty"`
ProjectURL string `json:"project_url,omitempty"` ProjectURL string `json:"project_url,omitempty"`
Keywords []string `json:"keywords,omitempty"` Keywords []string `json:"keywords,omitempty"`
Dependencies map[string]string `json:"dependencies,omitempty"` Dependencies map[string]string `json:"dependencies,omitempty"`

View File

@@ -35,9 +35,7 @@ func CherryPick(ctx *context.Context) {
ctx.Data["commit_message"] = "revert " + cherryPickCommit.Message() ctx.Data["commit_message"] = "revert " + cherryPickCommit.Message()
} else { } else {
ctx.Data["CherryPickType"] = "cherry-pick" ctx.Data["CherryPickType"] = "cherry-pick"
splits := strings.SplitN(cherryPickCommit.Message(), "\n", 2) ctx.Data["commit_summary"], ctx.Data["commit_message"], _ = strings.Cut(cherryPickCommit.Message(), "\n")
ctx.Data["commit_summary"] = splits[0]
ctx.Data["commit_message"] = splits[1]
} }
ctx.HTML(http.StatusOK, tplCherryPick) ctx.HTML(http.StatusOK, tplCherryPick)

View File

@@ -4,10 +4,8 @@
package sender package sender
import ( import (
"errors"
"io" "io"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
) )
type Sender interface { type Sender interface {
@@ -16,12 +14,7 @@ type Sender interface {
var Send = send var Send = send
func send(sender Sender, msgs ...*Message) error { func send(sender Sender, msg *Message) error {
if setting.MailService == nil {
log.Error("Mailer: Send is being invoked but mail service hasn't been initialized")
return nil
}
for _, msg := range msgs {
m := msg.ToMessage() m := msg.ToMessage()
froms := m.GetFrom() froms := m.GetFrom()
to, err := m.GetRecipients() to, err := m.GetRecipients()
@@ -30,9 +23,9 @@ func send(sender Sender, msgs ...*Message) error {
} }
// TODO: implement sending from multiple addresses // TODO: implement sending from multiple addresses
if err := sender.Send(froms[0].Address, to, m); err != nil { if len(froms) == 0 {
return err // FIXME: no idea why sometimes the "froms" can be empty, need to figure out the root problem
return errors.New("no FROM specified")
} }
} return sender.Send(froms[0].Address, to, m)
return nil
} }

View File

@@ -177,7 +177,7 @@ func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, t
} }
generatedContent := generateExpansion(ctx, string(content), templateRepo, generateRepo) generatedContent := generateExpansion(ctx, string(content), templateRepo, generateRepo)
substSubPath := filepath.Clean(filePathSanitize(generateExpansion(ctx, tmpDirSubPath, templateRepo, generateRepo))) substSubPath := filePathSanitize(generateExpansion(ctx, tmpDirSubPath, templateRepo, generateRepo))
newLocalPath := filepath.Join(tmpDir, substSubPath) newLocalPath := filepath.Join(tmpDir, substSubPath)
regular, err := util.IsRegularFile(newLocalPath) regular, err := util.IsRegularFile(newLocalPath)
if canWrite := regular || errors.Is(err, fs.ErrNotExist); !canWrite { if canWrite := regular || errors.Is(err, fs.ErrNotExist); !canWrite {
@@ -356,5 +356,5 @@ func filePathSanitize(s string) string {
} }
fields[i] = field fields[i] = field
} }
return filepath.FromSlash(strings.Join(fields, "/")) return filepath.Clean(filepath.FromSlash(strings.Trim(strings.Join(fields, "/"), "/")))
} }

View File

@@ -54,19 +54,24 @@ text/*.txt
} }
func TestFilePathSanitize(t *testing.T) { func TestFilePathSanitize(t *testing.T) {
assert.Equal(t, "test_CON", filePathSanitize("test_CON")) // path clean
assert.Equal(t, "test CON", filePathSanitize("test CON ")) assert.Equal(t, "a", filePathSanitize("//a/"))
assert.Equal(t, "__/traverse/__", filePathSanitize(".. /traverse/ ..")) assert.Equal(t, "_a", filePathSanitize(`\a`))
assert.Equal(t, "./__/a/_git/b_", filePathSanitize("./../a/.git/ b: ")) assert.Equal(t, "__/a/__", filePathSanitize(".. /a/ .."))
assert.Equal(t, "__/a/_git/b_", filePathSanitize("./../a/.git/ b: "))
// Windows reserved names
assert.Equal(t, "_", filePathSanitize("CoN")) assert.Equal(t, "_", filePathSanitize("CoN"))
assert.Equal(t, "_", filePathSanitize("LpT1")) assert.Equal(t, "_", filePathSanitize("LpT1"))
assert.Equal(t, "_", filePathSanitize("CoM1")) assert.Equal(t, "_", filePathSanitize("CoM1"))
assert.Equal(t, "test_CON", filePathSanitize("test_CON"))
assert.Equal(t, "test CON", filePathSanitize("test CON "))
// special chars
assert.Equal(t, "_", filePathSanitize("\u0000")) assert.Equal(t, "_", filePathSanitize("\u0000"))
assert.Equal(t, "目标", filePathSanitize("目标")) assert.Equal(t, ".", filePathSanitize(""))
// unlike filepath.Clean, it only sanitizes, doesn't change the separator layout
assert.Equal(t, "", filePathSanitize("")) //nolint:testifylint // for easy reading
assert.Equal(t, ".", filePathSanitize(".")) assert.Equal(t, ".", filePathSanitize("."))
assert.Equal(t, "/", filePathSanitize("/")) assert.Equal(t, ".", filePathSanitize("/"))
} }
func TestProcessGiteaTemplateFile(t *testing.T) { func TestProcessGiteaTemplateFile(t *testing.T) {

View File

@@ -4,7 +4,7 @@
<div class="ui form"> <div class="ui form">
<div class="field"> <div class="field">
<label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.pypi.install"}}</label> <label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.pypi.install"}}</label>
<div class="markup"><pre class="code-block"><code>pip install --index-url <origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/pypi/simple/"></origin-url> --extra-index-url https://pypi.org/ {{.PackageDescriptor.Package.Name}}</code></pre></div> <div class="markup"><pre class="code-block"><code>pip install --index-url <origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/pypi/simple/"></origin-url> --extra-index-url https://pypi.org/simple {{.PackageDescriptor.Package.Name}}</code></pre></div>
</div> </div>
<div class="field"> <div class="field">
<label>{{ctx.Locale.Tr "packages.registry.documentation" "PyPI" "https://docs.gitea.com/usage/packages/pypi/"}}</label> <label>{{ctx.Locale.Tr "packages.registry.documentation" "PyPI" "https://docs.gitea.com/usage/packages/pypi/"}}</label>