[gitea] week 2025-16 cherry pick (gitea/main -> forgejo) (#7602)

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7602
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
Gusted 2025-05-02 18:35:33 +00:00
commit 3ebd96ef73
10 changed files with 141 additions and 25 deletions

View file

@ -76,6 +76,10 @@ var microcmdUserCreate = &cli.Command{
Name: "restricted",
Usage: "Make a restricted user account",
},
&cli.StringFlag{
Name: "fullname",
Usage: `The full, human-readable name of the user`,
},
},
}
@ -161,6 +165,7 @@ func runCreateUser(c *cli.Context) error {
IsAdmin: isAdmin,
MustChangePassword: mustChangePassword,
Visibility: visibility,
FullName: c.String("fullname"),
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{

View file

@ -279,9 +279,7 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
default:
e.Desc("package_version.created_unix")
}
// Sort by id for stable order with duplicates in the other field
e.Asc("package_version.id")
e.Desc("package_version.id") // Sort by id for stable order with duplicates in the other field
}
// SearchVersions gets all versions of packages matching the search options

View file

@ -290,7 +290,24 @@ func DownloadManifest(ctx *context.Context) {
})
}
// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-6
// formFileOptionalReadCloser returns (nil, nil) if the formKey is not present.
func formFileOptionalReadCloser(ctx *context.Context, formKey string) (io.ReadCloser, error) {
multipartFile, _, err := ctx.Req.FormFile(formKey)
if err != nil && !errors.Is(err, http.ErrMissingFile) {
return nil, err
}
if multipartFile != nil {
return multipartFile, nil
}
content := ctx.Req.FormValue(formKey)
if content == "" {
return nil, nil
}
return io.NopCloser(strings.NewReader(content)), nil
}
// UploadPackageFile refers to https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-6
func UploadPackageFile(ctx *context.Context) {
packageScope := ctx.Params("scope")
packageName := ctx.Params("name")
@ -304,9 +321,9 @@ func UploadPackageFile(ctx *context.Context) {
packageVersion := v.Core().String()
file, _, err := ctx.Req.FormFile("source-archive")
if err != nil {
apiError(ctx, http.StatusBadRequest, err)
file, err := formFileOptionalReadCloser(ctx, "source-archive")
if file == nil || err != nil {
apiError(ctx, http.StatusBadRequest, "unable to read source-archive file")
return
}
defer file.Close()
@ -318,10 +335,13 @@ func UploadPackageFile(ctx *context.Context) {
}
defer buf.Close()
var mr io.Reader
metadata := ctx.Req.FormValue("metadata")
if metadata != "" {
mr = strings.NewReader(metadata)
mr, err := formFileOptionalReadCloser(ctx, "metadata")
if err != nil {
apiError(ctx, http.StatusBadRequest, "unable to read metadata file")
return
}
if mr != nil {
defer mr.Close()
}
pck, err := swift_module.ParsePackage(buf, buf.Size(), mr)

View file

@ -27,11 +27,14 @@ const (
// Create render the page for create organization
func Create(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_org.title")
ctx.Data["DefaultOrgVisibilityMode"] = setting.Service.DefaultOrgVisibilityMode
if !ctx.Doer.CanCreateOrganization() {
ctx.ServerError("Not allowed", errors.New(ctx.Locale.TrString("org.form.create_org_not_allowed")))
return
}
ctx.Data["visibility"] = setting.Service.DefaultOrgVisibilityMode
ctx.Data["repo_admin_change_team_access"] = true
ctx.HTML(http.StatusOK, tplCreateOrg)
}

View file

@ -401,6 +401,7 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
// GetPullDiffStats get Pull Requests diff stats
func GetPullDiffStats(ctx *context.Context) {
// FIXME: this getPullInfo seems to be a duplicate call with other route handlers
issue, ok := getPullInfo(ctx)
if !ok {
return
@ -408,15 +409,15 @@ func GetPullDiffStats(ctx *context.Context) {
pull := issue.PullRequest
mergeBaseCommitID := GetMergedBaseCommitID(ctx, issue)
if mergeBaseCommitID == "" {
ctx.NotFound("PullFiles", nil)
return
}
// do not report 500 server error to end users if error occurs, otherwise a PR missing ref won't be able to view.
headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
log.Error("Failed to GetRefCommitID: %v, repo: %v", err, ctx.Repo.Repository.FullName())
return
}

View file

@ -19,15 +19,15 @@
<span class="inline required field"><label for="visibility">{{ctx.Locale.Tr "org.settings.visibility"}}</label></span>
<div class="inline-grouped-list">
<div class="ui radio checkbox">
<input class="enable-system-radio" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}>
<input class="enable-system-radio" name="visibility" type="radio" value="0" {{if .visibility.IsPublic}}checked{{end}}>
<label>{{ctx.Locale.Tr "org.settings.visibility.public"}}</label>
</div>
<div class="ui radio checkbox">
<input class="enable-system-radio" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}>
<input class="enable-system-radio" name="visibility" type="radio" value="1" {{if .visibility.IsLimited}}checked{{end}}>
<label>{{ctx.Locale.Tr "org.settings.visibility.limited"}}</label>
</div>
<div class="ui radio checkbox">
<input class="enable-system-radio" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}>
<input class="enable-system-radio" name="visibility" type="radio" value="2" {{if .visibility.IsPrivate}}checked{{end}}>
<label>{{ctx.Locale.Tr "org.settings.visibility.private"}}</label>
</div>
</div>
@ -37,7 +37,7 @@
<span class="inline field"><label>{{ctx.Locale.Tr "org.settings.permission"}}</label></span>
<div class="inline-grouped-list">
<div class="ui checkbox">
<input type="checkbox" name="repo_admin_change_team_access" checked>
<input type="checkbox" name="repo_admin_change_team_access" {{if .repo_admin_change_team_access}}checked{{end}}>
<label>{{ctx.Locale.Tr "org.settings.repoadminchangeteam"}}</label>
</div>
</div>

View file

@ -45,7 +45,7 @@
{{if $.Page.LinkedPRs}}
{{range index $.Page.LinkedPRs .ID}}
<div class="meta tw-my-1">
<a href="{{$.Issue.Repo.Link}}/pulls/{{.Index}}">
<a href="{{.Repo.Link}}/pulls/{{.Index}}">
<span class="tw-m-0 text {{if .PullRequest.HasMerged}}purple{{else if .IsClosed}}red{{else}}green{{end}}">{{svg "octicon-git-merge" 16 "tw-mr-1 tw-align-middle"}}</span>
<span class="tw-align-middle">{{.Title}} <span class="text light grey">#{{.Index}}</span></span>
</a>

View file

@ -6,7 +6,7 @@
<div class="ui stackable grid">
<div class="ui eight wide column">
<div class="ui header">
<a class="file-revisions-btn ui basic button" title="{{ctx.Locale.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}"><span>{{.revision}}</span> {{svg "octicon-home"}}</a>
<a class="file-revisions-btn ui basic button" title="{{ctx.Locale.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}">{{if .revision}}<span>{{.revision}}</span> {{end}}{{svg "octicon-home"}}</a>
{{$title}}
<div class="ui sub header tw-break-anywhere">
{{$timeSince := DateUtils.TimeSince .Author.When}}

View file

@ -45,7 +45,7 @@
<div class="ui dividing header">
<div class="ui stackable grid">
<div class="eight wide column">
<a class="file-revisions-btn ui basic button" title="{{ctx.Locale.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" ><span>{{.CommitCount}}</span> {{svg "octicon-history"}}</a>
<a class="file-revisions-btn ui basic button" title="{{ctx.Locale.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" >{{if .CommitCount}}<span>{{.CommitCount}}</span> {{end}}{{svg "octicon-history"}}</a>
{{$title}}
<div class="ui sub header">
{{$timeSince := DateUtils.TimeSince .Author.When}}

View file

@ -35,6 +35,7 @@ func TestPackageSwift(t *testing.T) {
packageName := "test_package"
packageID := packageScope + "." + packageName
packageVersion := "1.0.3"
packageVersion2 := "1.0.4"
packageAuthor := "KN4CK3R"
packageDescription := "Gitea Test Package"
packageRepositoryURL := "https://gitea.io/gitea/gitea"
@ -184,6 +185,94 @@ func TestPackageSwift(t *testing.T) {
)
})
t.Run("UploadMultipart", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
uploadPackage := func(t *testing.T, url string, expectedStatus int, sr io.Reader, metadata string) {
var body bytes.Buffer
mpw := multipart.NewWriter(&body)
// Read the source archive content
sourceContent, err := io.ReadAll(sr)
require.NoError(t, err)
mpw.WriteField("source-archive", string(sourceContent))
if metadata != "" {
mpw.WriteField("metadata", metadata)
}
mpw.Close()
req := NewRequestWithBody(t, "PUT", url, &body).
SetHeader("Content-Type", mpw.FormDataContentType()).
SetHeader("Accept", swift_router.AcceptJSON).
AddBasicAuth(user.Name)
MakeRequest(t, req, expectedStatus)
}
createArchive := func(files map[string]string) *bytes.Buffer {
var buf bytes.Buffer
zw := zip.NewWriter(&buf)
for filename, content := range files {
w, _ := zw.Create(filename)
w.Write([]byte(content))
}
zw.Close()
return &buf
}
uploadURL := fmt.Sprintf("%s/%s/%s/%s", url, packageScope, packageName, packageVersion2)
req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
MakeRequest(t, req, http.StatusUnauthorized)
// Test with metadata as form field
uploadPackage(
t,
uploadURL,
http.StatusCreated,
createArchive(map[string]string{
"Package.swift": contentManifest1,
"Package@swift-5.6.swift": contentManifest2,
}),
`{"name":"`+packageName+`","version":"`+packageVersion2+`","description":"`+packageDescription+`","codeRepository":"`+packageRepositoryURL+`","author":{"givenName":"`+packageAuthor+`"},"repositoryURLs":["`+packageRepositoryURL+`"]}`,
)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeSwift)
require.NoError(t, err)
require.Len(t, pvs, 2) // ATTENTION: many subtests are unable to run separately, they depend on the results of previous tests
thisPackageVersion := pvs[0]
pd, err := packages.GetPackageDescriptor(db.DefaultContext, thisPackageVersion)
require.NoError(t, err)
assert.NotNil(t, pd.SemVer)
assert.Equal(t, packageID, pd.Package.Name)
assert.Equal(t, packageVersion2, pd.Version.Version)
assert.IsType(t, &swift_module.Metadata{}, pd.Metadata)
metadata := pd.Metadata.(*swift_module.Metadata)
assert.Equal(t, packageDescription, metadata.Description)
assert.Len(t, metadata.Manifests, 2)
assert.Equal(t, contentManifest1, metadata.Manifests[""].Content)
assert.Equal(t, contentManifest2, metadata.Manifests["5.6"].Content)
assert.Len(t, pd.VersionProperties, 1)
assert.Equal(t, packageRepositoryURL, pd.VersionProperties.GetByName(swift_module.PropertyRepositoryURL))
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, thisPackageVersion.ID)
require.NoError(t, err)
assert.Len(t, pfs, 1)
assert.Equal(t, fmt.Sprintf("%s-%s.zip", packageName, packageVersion2), pfs[0].Name)
assert.True(t, pfs[0].IsLead)
uploadPackage(
t,
uploadURL,
http.StatusConflict,
createArchive(map[string]string{
"Package.swift": contentManifest1,
}),
"",
)
})
t.Run("Download", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@ -212,7 +301,7 @@ func TestPackageSwift(t *testing.T) {
SetHeader("Accept", swift_router.AcceptJSON)
resp := MakeRequest(t, req, http.StatusOK)
versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion)
versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion2)
assert.Equal(t, "1", resp.Header().Get("Content-Version"))
assert.Equal(t, fmt.Sprintf(`<%s>; rel="latest-version"`, versionURL), resp.Header().Get("Link"))
@ -222,9 +311,9 @@ func TestPackageSwift(t *testing.T) {
var result *swift_router.EnumeratePackageVersionsResponse
DecodeJSON(t, resp, &result)
assert.Len(t, result.Releases, 1)
assert.Contains(t, result.Releases, packageVersion)
assert.Equal(t, versionURL, result.Releases[packageVersion].URL)
assert.Len(t, result.Releases, 2)
assert.Contains(t, result.Releases, packageVersion2)
assert.Equal(t, versionURL, result.Releases[packageVersion2].URL)
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.json", url, packageScope, packageName)).
AddBasicAuth(user.Name)