Merge branch 'forgejo' into feat/actions-logs-api

This commit is contained in:
zachhandley 2026-05-27 19:46:07 +02:00
commit f8efba782e
12 changed files with 221 additions and 58 deletions

View file

@ -32,7 +32,7 @@ jobs:
- uses: https://data.forgejo.org/actions/checkout@v6
- id: forgejo
uses: https://data.forgejo.org/actions/setup-forgejo@v3.1.11
uses: https://data.forgejo.org/actions/setup-forgejo@v3.1.12
with:
user: root
password: admin1234

View file

@ -459,6 +459,11 @@
"path": "github.com/chi-middleware/proxy/LICENSE",
"licenseText": "Copyright (c) 2020 Lauris BH\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
},
{
"name": "github.com/clipperhouse/uax29/v2/graphemes",
"path": "github.com/clipperhouse/uax29/v2/graphemes/LICENSE",
"licenseText": "MIT License\n\nCopyright (c) 2020 Matt Sherman\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
},
{
"name": "github.com/cloudflare/circl",
"path": "github.com/cloudflare/circl/LICENSE",

View file

@ -191,5 +191,24 @@ func main() {
}
}
if exitCode != 0 {
fmt.Println(dmp.DiffPrettyText([]diffmatchpatch.Diff{{
Type: diffmatchpatch.DiffEqual,
Text: "Please adjust the locale files as suggested above (",
}, {
Type: diffmatchpatch.DiffDelete,
Text: "red",
}, {
Type: diffmatchpatch.DiffEqual,
Text: ": removal, ",
}, {
Type: diffmatchpatch.DiffInsert,
Text: "green",
}, {
Type: diffmatchpatch.DiffEqual,
Text: ": insertion)",
}}))
}
os.Exit(exitCode)
}

13
go.mod
View file

@ -11,7 +11,7 @@ require (
code.forgejo.org/forgejo/go-rpmutils v1.0.0
code.forgejo.org/forgejo/levelqueue v1.1.0
code.forgejo.org/forgejo/reply v1.0.2
code.forgejo.org/forgejo/runner/v12 v12.10.1
code.forgejo.org/forgejo/runner/v12 v12.10.2
code.forgejo.org/go-chi/binding v1.0.1
code.forgejo.org/go-chi/cache v1.0.1
code.forgejo.org/go-chi/captcha v1.0.2
@ -76,7 +76,7 @@ require (
github.com/klauspost/compress v1.18.6
github.com/klauspost/cpuid/v2 v2.3.0
github.com/markbates/goth v1.82.0
github.com/mattn/go-isatty v0.0.21
github.com/mattn/go-isatty v0.0.22
github.com/mattn/go-sqlite3 v1.14.44
github.com/meilisearch/meilisearch-go v0.36.2
github.com/mholt/archives v0.1.5
@ -147,7 +147,7 @@ require (
github.com/blevesearch/zapx/v15 v15.4.3 // indirect
github.com/blevesearch/zapx/v16 v16.3.4 // indirect
github.com/blevesearch/zapx/v17 v17.1.2 // indirect
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect
@ -156,6 +156,7 @@ require (
github.com/caddyserver/zerossl v0.1.5 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.6.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
@ -165,7 +166,7 @@ require (
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c // indirect
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/color v1.19.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.1 // indirect
github.com/go-ap/errors v0.0.0-20260208110149-e1b309365966 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
@ -206,7 +207,7 @@ require (
github.com/mailru/easyjson v0.9.0 // indirect
github.com/markbates/going v1.0.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.21 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mholt/acmez/v3 v3.1.6 // indirect
github.com/miekg/dns v1.1.72 // indirect
@ -232,7 +233,7 @@ require (
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rhysd/actionlint v1.7.10 // indirect
github.com/rhysd/actionlint v1.7.12 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/rs/xid v1.6.0 // indirect

27
go.sum
View file

@ -30,8 +30,8 @@ code.forgejo.org/forgejo/levelqueue v1.1.0 h1:IgDbeZBdzJhbI8M0hXCQ1qyJIk83cGnBS3
code.forgejo.org/forgejo/levelqueue v1.1.0/go.mod h1:flCo3rqxrybUXQR2I8TFyiDSsLkOjb71CZOEdAuJmgc=
code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ=
code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U=
code.forgejo.org/forgejo/runner/v12 v12.10.1 h1:qRKjWItVDc2lEMl3jGlKyFpqgX4xHeOdEyl/irO/Nk8=
code.forgejo.org/forgejo/runner/v12 v12.10.1/go.mod h1:A51GyZJlril5cIpVMvOn3NqE8upOE6ePjwC6s31kRHk=
code.forgejo.org/forgejo/runner/v12 v12.10.2 h1:tU4XiBlmMpQwutKL5QYV1FRTkv2FPrbuymYsucNdNWE=
code.forgejo.org/forgejo/runner/v12 v12.10.2/go.mod h1:QnCx84rMQJ+DJ4aS9r2BZL0z2a0ZFaVl9EfMnXYl23g=
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA=
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
code.forgejo.org/go-chi/binding v1.0.1 h1:coKNI+X1NzRN7X85LlrpvBRqk0TXpJ+ja28vusQWEuY=
@ -145,8 +145,8 @@ github.com/blevesearch/zapx/v16 v16.3.4 h1:hDAqA8qusZTNbPEL7//w5P65UZ2de6yhSeUaT
github.com/blevesearch/zapx/v16 v16.3.4/go.mod h1:zqkPPqs9GS9FzVWzCO3Wf1X044yWAV17+4zb+FTiEHg=
github.com/blevesearch/zapx/v17 v17.1.2 h1:avbOk2igaASNoiy0BE/jPgcxAnRI2PGeydeP4hg7Ikk=
github.com/blevesearch/zapx/v17 v17.1.2/go.mod h1:WQObxKrqUX7cd0G1GMvDfc/bmZzQvoy7APOPimx7DiI=
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
@ -185,6 +185,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -242,8 +244,8 @@ github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTe
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
@ -510,10 +512,10 @@ github.com/markbates/goth v1.82.0 h1:8j/c34AjBSTNzO7zTsOyP5IYCQCMBTRBHAbBt/PI0bQ
github.com/markbates/goth v1.82.0/go.mod h1:/DRlcq0pyqkKToyZjsL2KgiA1zbF1HIjE7u2uC79rUk=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ=
github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8=
@ -604,9 +606,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k=
github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
github.com/rhysd/actionlint v1.7.10 h1:FL3XIEs72G4/++168vlv5FKOWMSWvWIQw1kBCadyOcM=
github.com/rhysd/actionlint v1.7.10/go.mod h1:ZHX/hrmknlsJN73InPTKsKdXpAv9wVdrJy8h8HAwFHg=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rhysd/actionlint v1.7.12 h1:vQ4GeJN86C0QH+gTUQcs8McmK62OLT3kmakPMtEWYnY=
github.com/rhysd/actionlint v1.7.12/go.mod h1:krOUhujIsJusovkaYzQ/VNH8PFexjNKqU0q5XI/4w+g=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=

View file

@ -76,22 +76,35 @@ func ExistPackages(ctx context.Context, opts *PackageSearchOptions) (bool, error
// SearchPackages gets the packages matching the search options
func SearchPackages(ctx context.Context, opts *PackageSearchOptions, iter func(*packages.PackageFileDescriptor)) error {
return db.GetEngine(ctx).
// Forgejo's db library doesn't have an iterate method that allows us to do this query, *sorted*, in chunks. xorm's
// `Iterate` isn't usable because sometimes we are in a transaction, and GetPackageFileDescriptor will make
// supplemental DB calls which will fail in xorm's Iterate as the same connection will come back from
// db.GetEngine(ctx) due to the transaction, and that connection is already being used for the iterate.
//
// Aside from the reasons we can't do this iteratively, `SearchPackages` is only used when we're rebuilding the
// package index, and the caller `buildPackagesIndices` is already building *three* in-memory files referencing all
// this same information -- so the memory usage to load this information in one chunk shouldn't be significantly
// worse than the index rebuild side anyway.
pfs := make([]*packages.PackageFile, 0, 100)
err := db.GetEngine(ctx).
Table("package_file").
Select("package_file.*").
Join("INNER", "package_version", "package_version.id = package_file.version_id").
Join("INNER", "package", "package.id = package_version.package_id").
Where(opts.toCond()).
Asc("package.lower_name", "package_version.created_unix").
Iterate(&packages.PackageFile{}, func(i int, bean any) error {
pf := bean.(*packages.PackageFile)
pfd, err := packages.GetPackageFileDescriptor(ctx, pf)
if err != nil {
return err
}
iter(pfd)
return nil
})
Find(&pfs)
if err != nil {
return err
}
for _, pf := range pfs {
pfd, err := packages.GetPackageFileDescriptor(ctx, pf)
if err != nil {
return err
}
iter(pfd)
}
return nil
}
// GetDistributions gets all available distributions

8
package-lock.json generated
View file

@ -43,7 +43,7 @@
"chart.js": "4.5.1",
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.15",
"clippie": "4.2.0",
"css-loader": "7.1.3",
"dayjs": "1.11.19",
"dropzone": "6.0.0-beta.2",
@ -6296,9 +6296,9 @@
}
},
"node_modules/clippie": {
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/clippie/-/clippie-4.1.15.tgz",
"integrity": "sha512-K4z5MF32z7Gr1fUcfuUZvmrzpdNs5q8zAm2yqsWhA8mZ9Q6GL4HNdR2k3h3ubEEEGoyb8fvMA48LDr2MKYDASA==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/clippie/-/clippie-4.2.0.tgz",
"integrity": "sha512-NcWaVzqChJ69+foFhwJXta3KXWNDJlpicxcfZG5udobyszOSBDhmFubKv1b/1nIZiVAsPoKqME2iV1SITZqFoQ==",
"license": "BSD-2-Clause"
},
"node_modules/cliui": {

View file

@ -42,7 +42,7 @@
"chart.js": "4.5.1",
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.15",
"clippie": "4.2.0",
"css-loader": "7.1.3",
"dayjs": "1.11.19",
"dropzone": "6.0.0-beta.2",

View file

@ -183,7 +183,7 @@ func BatchHandler(ctx *context.Context) {
}
if isUpload {
ok, err := quota_model.EvaluateForUser(ctx, ctx.Doer.ID, quota_model.LimitSubjectSizeGitLFS)
ok, err := quota_model.EvaluateForUser(ctx, repository.OwnerID, quota_model.LimitSubjectSizeGitLFS)
if err != nil {
log.Error("quota_model.EvaluateForUser: %v", err)
writeStatus(ctx, http.StatusInternalServerError)
@ -191,6 +191,7 @@ func BatchHandler(ctx *context.Context) {
}
if !ok {
writeStatusMessage(ctx, http.StatusRequestEntityTooLarge, "quota exceeded")
return
}
}
@ -317,8 +318,8 @@ func UploadHandler(ctx *context.Context) {
return
}
if exists {
ok, err := quota_model.EvaluateForUser(ctx, ctx.Doer.ID, quota_model.LimitSubjectSizeGitLFS)
if !exists {
ok, err := quota_model.EvaluateForUser(ctx, repository.OwnerID, quota_model.LimitSubjectSizeGitLFS)
if err != nil {
log.Error("quota_model.EvaluateForUser: %v", err)
writeStatus(ctx, http.StatusInternalServerError)
@ -326,6 +327,7 @@ func UploadHandler(ctx *context.Context) {
}
if !ok {
writeStatusMessage(ctx, http.StatusRequestEntityTooLarge, "quota exceeded")
return
}
}

View file

@ -528,9 +528,7 @@ func TestPackageCleanup(t *testing.T) {
duration, _ := time.ParseDuration("-1h")
t.Run("Debian", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// Debian does a repository rebuild.
// Debian does a repository rebuild; these tests cover validation of that process.
distribution := "forgejo"
component := "main"
architecture := "amd64"
@ -540,27 +538,64 @@ func TestPackageCleanup(t *testing.T) {
rootURL := fmt.Sprintf("/api/packages/%s/debian", user.Name)
uploadURL := fmt.Sprintf("%s/pool/%s/%s/upload", rootURL, distribution, component)
req := NewRequestWithBody(t, "PUT", uploadURL,
createDebianArchive(packageName, "1.0.0", architecture, packageDescription)).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusCreated)
t.Run("empty repository after cleanup", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
resp := MakeRequest(t, NewRequestf(t, "GET", "%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture), http.StatusOK)
assert.Contains(t, resp.Body.String(), "pool/forgejo/main/runner_1.0.0_amd64.deb")
req := NewRequestWithBody(t, "PUT", uploadURL,
createDebianArchive(packageName, "1.0.0", architecture, packageDescription)).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusCreated)
pcr, err := packages_model.InsertCleanupRule(t.Context(), &packages_model.PackageCleanupRule{
Enabled: true,
RemovePattern: `.+`,
OwnerID: user.ID,
Type: packages_model.TypeDebian,
resp := MakeRequest(t, NewRequestf(t, "GET", "%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture), http.StatusOK)
assert.Contains(t, resp.Body.String(), "pool/forgejo/main/runner_1.0.0_amd64.deb")
pcr, err := packages_model.InsertCleanupRule(t.Context(), &packages_model.PackageCleanupRule{
Enabled: true,
RemovePattern: `.+`,
OwnerID: user.ID,
Type: packages_model.TypeDebian,
})
require.NoError(t, err)
require.NoError(t, packages_cleanup_service.CleanupTask(t.Context(), duration))
MakeRequest(t, NewRequestf(t, "GET", "%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture), http.StatusNotFound)
require.NoError(t, packages_model.DeleteCleanupRuleByID(t.Context(), pcr.ID))
})
require.NoError(t, err)
require.NoError(t, packages_cleanup_service.CleanupTask(t.Context(), duration))
t.Run("non-empty repository after cleanup", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
MakeRequest(t, NewRequestf(t, "GET", "%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture), http.StatusNotFound)
req := NewRequestWithBody(t, "PUT", uploadURL,
createDebianArchive(packageName, "1.0.0", architecture, packageDescription)).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusCreated)
req = NewRequestWithBody(t, "PUT", uploadURL,
createDebianArchive(packageName, "1.0.1", architecture, packageDescription)).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusCreated)
require.NoError(t, packages_model.DeleteCleanupRuleByID(t.Context(), pcr.ID))
resp := MakeRequest(t, NewRequestf(t, "GET", "%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture), http.StatusOK)
assert.Contains(t, resp.Body.String(), "pool/forgejo/main/runner_1.0.0_amd64.deb")
assert.Contains(t, resp.Body.String(), "pool/forgejo/main/runner_1.0.1_amd64.deb")
pcr, err := packages_model.InsertCleanupRule(t.Context(), &packages_model.PackageCleanupRule{
Enabled: true,
RemovePattern: `.+`,
OwnerID: user.ID,
Type: packages_model.TypeDebian,
KeepCount: 1,
})
require.NoError(t, err)
require.NoError(t, packages_cleanup_service.CleanupTask(t.Context(), duration))
resp = MakeRequest(t, NewRequestf(t, "GET", "%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture), http.StatusOK)
assert.Contains(t, resp.Body.String(), "pool/forgejo/main/runner_1.0.1_amd64.deb")
require.NoError(t, packages_model.DeleteCleanupRuleByID(t.Context(), pcr.ID))
})
})
t.Run("Common", func(t *testing.T) {

View file

@ -16,11 +16,13 @@ import (
"testing"
"forgejo.org/models/db"
git_model "forgejo.org/models/git"
org_model "forgejo.org/models/organization"
quota_model "forgejo.org/models/quota"
repo_model "forgejo.org/models/repo"
user_model "forgejo.org/models/user"
"forgejo.org/modules/git"
"forgejo.org/modules/lfs"
"forgejo.org/modules/setting"
api "forgejo.org/modules/structs"
"forgejo.org/modules/test"
@ -365,7 +367,7 @@ func TestWebQuotaEnforcementRepoTransfer(t *testing.T) {
})
}
func TestGitQuotaEnforcement(t *testing.T) {
func TestQuotaGitEnforcement(t *testing.T) {
onApplicationRun(t, func(t *testing.T, u *url.URL) {
env := createQuotaWebEnv(t)
defer env.Cleanup()
@ -548,6 +550,55 @@ func TestGitQuotaEnforcement(t *testing.T) {
})
}
func TestQuotaGitLfsEnforcement(t *testing.T) {
defer test.MockVariableValue(&setting.LFS.StartServer, true)()
onApplicationRun(t, func(t *testing.T, u *url.URL) {
env := createQuotaWebEnv(t)
defer env.Cleanup()
t.Run("UploadHandler", func(t *testing.T) {
// Uploading to our repo => 413
env.As(t, env.Users.Limited).
With(Context{Repo: env.Users.Limited.Repo}).
PushLFSObject().
ExpectStatus(http.StatusRequestEntityTooLarge)
// Uploading to the limited org repo => 413
env.As(t, env.Users.Limited).
With(Context{Repo: env.Orgs.Limited.Repo}).
PushLFSObject().
ExpectStatus(http.StatusRequestEntityTooLarge)
// Uploading to the unlimited org repo => 200
env.As(t, env.Users.Limited).
With(Context{Repo: env.Orgs.Unlimited.Repo}).
PushLFSObject().
ExpectStatus(http.StatusOK)
})
t.Run("BatchHandler", func(t *testing.T) {
// Uploading to our repo => 413
env.As(t, env.Users.Limited).
With(Context{Repo: env.Users.Limited.Repo}).
BatchPushLFSObject().
ExpectStatus(http.StatusRequestEntityTooLarge)
// Uploading to the limited org repo => 413
env.As(t, env.Users.Limited).
With(Context{Repo: env.Orgs.Limited.Repo}).
BatchPushLFSObject().
ExpectStatus(http.StatusRequestEntityTooLarge)
// Uploading to the unlimited org repo => 200
env.As(t, env.Users.Limited).
With(Context{Repo: env.Orgs.Unlimited.Repo}).
BatchPushLFSObject().
ExpectStatus(http.StatusOK)
})
})
}
func TestQuotaConfigDefault(t *testing.T) {
onApplicationRun(t, func(t *testing.T, u *url.URL) {
env := createQuotaWebEnv(t)
@ -793,6 +844,42 @@ func (ctx *quotaWebEnvAsContext) CreateReleaseAttachment(filename string) *quota
return ctx.CreateAttachment(filename, "releases")
}
func (ctx *quotaWebEnvAsContext) PushLFSObject() *quotaWebEnvAsContext {
ctx.t.Helper()
p := lfs.Pointer{Oid: "6ccce4863b70f258d691f59609d31b4502e1ba5199942d3bc5d35d17a4ce771d", Size: 5}
ctx.request = NewRequestWithBody(ctx.t, "PUT",
fmt.Sprintf("%s.git/info/lfs/objects/%s/%d",
ctx.Repo.Link(), p.Oid, p.Size), strings.NewReader("gitea"))
ctx.t.Cleanup(func() {
git_model.RemoveLFSMetaObjectByOid(db.DefaultContext, ctx.Repo.ID, p.Oid)
})
return ctx
}
func (ctx *quotaWebEnvAsContext) BatchPushLFSObject() *quotaWebEnvAsContext {
ctx.t.Helper()
batch := &lfs.BatchRequest{
Operation: "upload",
Objects: []lfs.Pointer{
{Oid: "d6f175817f886ec6fbbc1515326465fa96c3bfd54a4ea06cfd6dbbd8340e0153", Size: 1},
},
}
ctx.request = NewRequestWithJSON(ctx.t, "POST",
fmt.Sprintf("%s.git/info/lfs/objects/batch", ctx.Repo.Link()), batch).
SetHeader("Accept", lfs.AcceptHeader).
SetHeader("Content-Type", lfs.MediaType)
ctx.t.Cleanup(func() {
git_model.RemoveLFSMetaObjectByOid(db.DefaultContext, ctx.Repo.ID, batch.Objects[0].Oid)
})
return ctx
}
func (ctx *quotaWebEnvAsContext) WithoutQuota(task func(ctx *quotaWebEnvAsContext)) *quotaWebEnvAsContext {
ctx.t.Helper()

View file

@ -177,8 +177,8 @@
white-space: nowrap;
}
#workflow_dispatch_dropdown .menu {
/* FIXME: max-height is ineffective without `overflow:`, but clipping overflow breaks dropdown menus */
max-height: 500px;
overflow-inline: auto;
}
@media (max-width: 640px) or (767.98px < width < 854px) {
#workflow_dispatch_dropdown .menu {