Skip to content

Commit 60f175f

Browse files
GiteaBotwgr1984wxiaoguang
authored
Swift files can be passed either as file or as form value (#34068) (#34236)
Backport #34068 by wgr1984 Fix #33990 Co-authored-by: Wolfgang Reithmeier <[email protected]> Co-authored-by: wxiaoguang <[email protected]>
1 parent 260816d commit 60f175f

File tree

3 files changed

+123
-15
lines changed

3 files changed

+123
-15
lines changed

models/packages/package_version.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,7 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
279279
default:
280280
e.Desc("package_version.created_unix")
281281
}
282-
283-
// Sort by id for stable order with duplicates in the other field
284-
e.Asc("package_version.id")
282+
e.Desc("package_version.id") // Sort by id for stable order with duplicates in the other field
285283
}
286284

287285
// SearchVersions gets all versions of packages matching the search options

routers/api/packages/swift/swift.go

+28-8
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,24 @@ func DownloadManifest(ctx *context.Context) {
290290
})
291291
}
292292

293-
// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-6
293+
// formFileOptionalReadCloser returns (nil, nil) if the formKey is not present.
294+
func formFileOptionalReadCloser(ctx *context.Context, formKey string) (io.ReadCloser, error) {
295+
multipartFile, _, err := ctx.Req.FormFile(formKey)
296+
if err != nil && !errors.Is(err, http.ErrMissingFile) {
297+
return nil, err
298+
}
299+
if multipartFile != nil {
300+
return multipartFile, nil
301+
}
302+
303+
content := ctx.Req.FormValue(formKey)
304+
if content == "" {
305+
return nil, nil
306+
}
307+
return io.NopCloser(strings.NewReader(ctx.Req.FormValue(formKey))), nil
308+
}
309+
310+
// UploadPackageFile refers to https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-6
294311
func UploadPackageFile(ctx *context.Context) {
295312
packageScope := ctx.PathParam("scope")
296313
packageName := ctx.PathParam("name")
@@ -304,9 +321,9 @@ func UploadPackageFile(ctx *context.Context) {
304321

305322
packageVersion := v.Core().String()
306323

307-
file, _, err := ctx.Req.FormFile("source-archive")
308-
if err != nil {
309-
apiError(ctx, http.StatusBadRequest, err)
324+
file, err := formFileOptionalReadCloser(ctx, "source-archive")
325+
if file == nil || err != nil {
326+
apiError(ctx, http.StatusBadRequest, "unable to read source-archive file")
310327
return
311328
}
312329
defer file.Close()
@@ -318,10 +335,13 @@ func UploadPackageFile(ctx *context.Context) {
318335
}
319336
defer buf.Close()
320337

321-
var mr io.Reader
322-
metadata := ctx.Req.FormValue("metadata")
323-
if metadata != "" {
324-
mr = strings.NewReader(metadata)
338+
mr, err := formFileOptionalReadCloser(ctx, "metadata")
339+
if err != nil {
340+
apiError(ctx, http.StatusBadRequest, "unable to read metadata file")
341+
return
342+
}
343+
if mr != nil {
344+
defer mr.Close()
325345
}
326346

327347
pck, err := swift_module.ParsePackage(buf, buf.Size(), mr)

tests/integration/api_packages_swift_test.go

+94-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"code.gitea.io/gitea/tests"
2424

2525
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/require"
2627
)
2728

2829
func TestPackageSwift(t *testing.T) {
@@ -34,6 +35,7 @@ func TestPackageSwift(t *testing.T) {
3435
packageName := "test_package"
3536
packageID := packageScope + "." + packageName
3637
packageVersion := "1.0.3"
38+
packageVersion2 := "1.0.4"
3739
packageAuthor := "KN4CK3R"
3840
packageDescription := "Gitea Test Package"
3941
packageRepositoryURL := "https://gitea.io/gitea/gitea"
@@ -183,6 +185,94 @@ func TestPackageSwift(t *testing.T) {
183185
)
184186
})
185187

188+
t.Run("UploadMultipart", func(t *testing.T) {
189+
defer tests.PrintCurrentTest(t)()
190+
191+
uploadPackage := func(t *testing.T, url string, expectedStatus int, sr io.Reader, metadata string) {
192+
var body bytes.Buffer
193+
mpw := multipart.NewWriter(&body)
194+
195+
// Read the source archive content
196+
sourceContent, err := io.ReadAll(sr)
197+
assert.NoError(t, err)
198+
mpw.WriteField("source-archive", string(sourceContent))
199+
200+
if metadata != "" {
201+
mpw.WriteField("metadata", metadata)
202+
}
203+
204+
mpw.Close()
205+
206+
req := NewRequestWithBody(t, "PUT", url, &body).
207+
SetHeader("Content-Type", mpw.FormDataContentType()).
208+
SetHeader("Accept", swift_router.AcceptJSON).
209+
AddBasicAuth(user.Name)
210+
MakeRequest(t, req, expectedStatus)
211+
}
212+
213+
createArchive := func(files map[string]string) *bytes.Buffer {
214+
var buf bytes.Buffer
215+
zw := zip.NewWriter(&buf)
216+
for filename, content := range files {
217+
w, _ := zw.Create(filename)
218+
w.Write([]byte(content))
219+
}
220+
zw.Close()
221+
return &buf
222+
}
223+
224+
uploadURL := fmt.Sprintf("%s/%s/%s/%s", url, packageScope, packageName, packageVersion2)
225+
226+
req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
227+
MakeRequest(t, req, http.StatusUnauthorized)
228+
229+
// Test with metadata as form field
230+
uploadPackage(
231+
t,
232+
uploadURL,
233+
http.StatusCreated,
234+
createArchive(map[string]string{
235+
"Package.swift": contentManifest1,
236+
"[email protected]": contentManifest2,
237+
}),
238+
`{"name":"`+packageName+`","version":"`+packageVersion2+`","description":"`+packageDescription+`","codeRepository":"`+packageRepositoryURL+`","author":{"givenName":"`+packageAuthor+`"},"repositoryURLs":["`+packageRepositoryURL+`"]}`,
239+
)
240+
241+
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeSwift)
242+
assert.NoError(t, err)
243+
require.Len(t, pvs, 2) // ATTENTION: many subtests are unable to run separately, they depend on the results of previous tests
244+
thisPackageVersion := pvs[0]
245+
pd, err := packages.GetPackageDescriptor(db.DefaultContext, thisPackageVersion)
246+
assert.NoError(t, err)
247+
assert.NotNil(t, pd.SemVer)
248+
assert.Equal(t, packageID, pd.Package.Name)
249+
assert.Equal(t, packageVersion2, pd.Version.Version)
250+
assert.IsType(t, &swift_module.Metadata{}, pd.Metadata)
251+
metadata := pd.Metadata.(*swift_module.Metadata)
252+
assert.Equal(t, packageDescription, metadata.Description)
253+
assert.Len(t, metadata.Manifests, 2)
254+
assert.Equal(t, contentManifest1, metadata.Manifests[""].Content)
255+
assert.Equal(t, contentManifest2, metadata.Manifests["5.6"].Content)
256+
assert.Len(t, pd.VersionProperties, 1)
257+
assert.Equal(t, packageRepositoryURL, pd.VersionProperties.GetByName(swift_module.PropertyRepositoryURL))
258+
259+
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, thisPackageVersion.ID)
260+
assert.NoError(t, err)
261+
assert.Len(t, pfs, 1)
262+
assert.Equal(t, fmt.Sprintf("%s-%s.zip", packageName, packageVersion2), pfs[0].Name)
263+
assert.True(t, pfs[0].IsLead)
264+
265+
uploadPackage(
266+
t,
267+
uploadURL,
268+
http.StatusConflict,
269+
createArchive(map[string]string{
270+
"Package.swift": contentManifest1,
271+
}),
272+
"",
273+
)
274+
})
275+
186276
t.Run("Download", func(t *testing.T) {
187277
defer tests.PrintCurrentTest(t)()
188278

@@ -211,7 +301,7 @@ func TestPackageSwift(t *testing.T) {
211301
SetHeader("Accept", swift_router.AcceptJSON)
212302
resp := MakeRequest(t, req, http.StatusOK)
213303

214-
versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion)
304+
versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion2)
215305

216306
assert.Equal(t, "1", resp.Header().Get("Content-Version"))
217307
assert.Equal(t, fmt.Sprintf(`<%s>; rel="latest-version"`, versionURL), resp.Header().Get("Link"))
@@ -221,9 +311,9 @@ func TestPackageSwift(t *testing.T) {
221311
var result *swift_router.EnumeratePackageVersionsResponse
222312
DecodeJSON(t, resp, &result)
223313

224-
assert.Len(t, result.Releases, 1)
225-
assert.Contains(t, result.Releases, packageVersion)
226-
assert.Equal(t, versionURL, result.Releases[packageVersion].URL)
314+
assert.Len(t, result.Releases, 2)
315+
assert.Contains(t, result.Releases, packageVersion2)
316+
assert.Equal(t, versionURL, result.Releases[packageVersion2].URL)
227317

228318
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.json", url, packageScope, packageName)).
229319
AddBasicAuth(user.Name)

0 commit comments

Comments
 (0)