From a12a5f3652c339b17b187ff424a480631a3c1e1e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 23 Jul 2023 17:56:43 +0800 Subject: [PATCH 01/11] Fix duplicated url prefix on issue context menu (#26066) Fix #26060 --- templates/repo/issue/view_content/context_menu.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/issue/view_content/context_menu.tmpl b/templates/repo/issue/view_content/context_menu.tmpl index 296668c9e0..ed22bc878b 100644 --- a/templates/repo/issue/view_content/context_menu.tmpl +++ b/templates/repo/issue/view_content/context_menu.tmpl @@ -10,7 +10,7 @@ {{else}} {{$referenceUrl = printf "%s/files#%s" .ctxData.Issue.Link .item.HashTag}} {{end}} -
{{.ctxData.locale.Tr "repo.issues.context.copy_link"}}
+
{{.ctxData.locale.Tr "repo.issues.context.copy_link"}}
{{.ctxData.locale.Tr "repo.issues.context.quote_reply"}}
{{if not .ctxData.UnitIssuesGlobalDisabled}}
{{.ctxData.locale.Tr "repo.issues.context.reference_issue"}}
From 4e4a71f3a089451a72ff3f8fd65d3d66060ce03d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 24 Jul 2023 00:27:48 +0000 Subject: [PATCH 02/11] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 34e6488db9..20ef4cde69 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1673,7 +1673,7 @@ pulls.is_empty=As modificações feitas neste ramo já existem no ramo de destin pulls.required_status_check_failed=Algumas das verificações obrigatórias não foram bem sucedidas. pulls.required_status_check_missing=Estão faltando algumas verificações necessárias. pulls.required_status_check_administrator=Uma vez que é administrador, ainda pode realizar a integração deste pedido. -pulls.blocked_by_approvals=Este pedido de integração ainda não tem aprovações suficientes. Já foram concedidas %d de um total de%d aprovações. +pulls.blocked_by_approvals=Este pedido de integração ainda não tem aprovações suficientes. Já foram concedidas %d de um total de %d aprovações. pulls.blocked_by_rejection=Este pedido de integração tem modificações solicitadas por um revisor oficial. pulls.blocked_by_official_review_requests=Este pedido de integração tem pedidos de revisão oficiais. pulls.blocked_by_outdated_branch=Este pedido de integração foi bloqueado por ser obsoleto. From 24c3bb95acfd906dc752f867615dafd170176502 Mon Sep 17 00:00:00 2001 From: HesterG Date: Mon, 24 Jul 2023 09:05:16 +0800 Subject: [PATCH 03/11] Categorize admin settings sidebar panel (#26030) This PR reorganize and categorize the admin settings sidebar panel into groups: - User Accounts, User Emails, Organizations, Authentication Sources -> Identity & Access - Repositories, Packages -> Code Assets - Webhooks, Applications -> Integrations Before: Screen Shot 2023-07-21 at 10 30 28 After: all configurable settings enabled (package, oauth, webhook) Screen Shot 2023-07-21 at 10 27 30 all configurable settings disabled (package, oauth, webhook) Screen Shot 2023-07-21 at 10 25 19 only oauth enabled Screen Shot 2023-07-21 at 10 26 23 only webhook enabled Screen Shot 2023-07-21 at 10 26 55 --- options/locale/locale_en-US.ini | 3 ++ templates/admin/navbar.tmpl | 77 ++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 94ae490981..24be7e0fc3 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2627,10 +2627,13 @@ teams.invite.description = Please click the button below to join the team. [admin] dashboard = Dashboard +identity_access = Identity & Access users = User Accounts organizations = Organizations +assets = Code Assets repositories = Repositories hooks = Webhooks +integrations = Integrations authentication = Authentication Sources emails = User Emails config = Configuration diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl index a96e5c9367..4cfdbac73f 100644 --- a/templates/admin/navbar.tmpl +++ b/templates/admin/navbar.tmpl @@ -4,35 +4,60 @@ {{.locale.Tr "admin.dashboard"}} - - {{.locale.Tr "admin.users"}} - - - {{.locale.Tr "admin.organizations"}} - - - {{.locale.Tr "admin.repositories"}} - - {{if .EnablePackages}} - - {{.locale.Tr "packages.title"}} - - {{end}} - {{if not DisableWebhooks}} +
+ {{.locale.Tr "admin.identity_access"}} + +
+
+ {{.locale.Tr "admin.assets"}} + +
+ + {{if and (not DisableWebhooks) .EnableOAuth2}} +
+ {{.locale.Tr "admin.integrations"}} + +
+ {{else}} + {{if not DisableWebhooks}} {{.locale.Tr "admin.hooks"}} - {{end}} - - {{.locale.Tr "admin.authentication"}} - - - {{.locale.Tr "admin.emails"}} - - {{if .EnableOAuth2}} - - {{.locale.Tr "settings.applications"}} - + {{end}} + {{if .EnableOAuth2}} + + {{.locale.Tr "settings.applications"}} + + {{end}} {{end}} {{if .EnableActions}}
From f3d41c61eb0e66aacc269508d27716425673509b Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 24 Jul 2023 05:47:27 +0200 Subject: [PATCH 04/11] Remove `db.DefaultContext` in `routers/` and `cmd/` (#26076) Now, the only remaining usages of `models.db.DefaultContext` are in - `modules` - `models` - `services` --- cmd/admin.go | 9 +- routers/api/packages/composer/composer.go | 2 +- routers/api/packages/conan/conan.go | 108 ++++++++++---------- routers/api/packages/container/blob.go | 20 ++-- routers/api/packages/container/container.go | 10 +- routers/api/packages/container/manifest.go | 24 ++--- routers/api/packages/npm/npm.go | 68 ++++++------ routers/api/v1/user/key.go | 3 +- routers/web/admin/packages.go | 2 +- routers/web/healthcheck/check.go | 7 +- routers/web/repo/view.go | 8 +- 11 files changed, 127 insertions(+), 134 deletions(-) diff --git a/cmd/admin.go b/cmd/admin.go index add3d67d74..ea62075093 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -5,6 +5,7 @@ package cmd import ( + "context" "errors" "fmt" "net/url" @@ -373,7 +374,7 @@ func runRepoSyncReleases(_ *cli.Context) error { continue } - oldnum, err := getReleaseCount(repo.ID) + oldnum, err := getReleaseCount(ctx, repo.ID) if err != nil { log.Warn(" GetReleaseCountByRepoID: %v", err) } @@ -385,7 +386,7 @@ func runRepoSyncReleases(_ *cli.Context) error { continue } - count, err = getReleaseCount(repo.ID) + count, err = getReleaseCount(ctx, repo.ID) if err != nil { log.Warn(" GetReleaseCountByRepoID: %v", err) gitRepo.Close() @@ -401,9 +402,9 @@ func runRepoSyncReleases(_ *cli.Context) error { return nil } -func getReleaseCount(id int64) (int64, error) { +func getReleaseCount(ctx context.Context, id int64) (int64, error) { return repo_model.GetReleaseCountByRepoID( - db.DefaultContext, + ctx, id, repo_model.FindReleasesOptions{ IncludeTags: true, diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index bf5bda743f..75bbfdf4d3 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -114,7 +114,7 @@ func SearchPackages(ctx *context.Context) { // EnumeratePackages lists all package names // https://packagist.org/apidoc#list-packages func EnumeratePackages(ctx *context.Context) { - ps, err := packages_model.GetPackagesByType(db.DefaultContext, ctx.Package.Owner.ID, packages_model.TypeComposer) + ps, err := packages_model.GetPackagesByType(ctx, ctx.Package.Owner.ID, packages_model.TypeComposer) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index 6e1727fd76..d7349a84b2 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -4,6 +4,7 @@ package conan import ( + std_ctx "context" "fmt" "io" "net/http" @@ -602,69 +603,64 @@ func DeletePackageV2(ctx *context.Context) { } func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeReference, ignoreRecipeRevision bool, pref *conan_module.PackageReference, ignorePackageRevision bool) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() + var pd *packages_model.PackageDescriptor + versionDeleted := false - pv, err := packages_model.GetVersionByNameAndVersion(ctx, apictx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version) - if err != nil { - return err - } - - pd, err := packages_model.GetPackageDescriptor(ctx, pv) - if err != nil { - return err - } - - filter := map[string]string{ - conan_module.PropertyRecipeUser: rref.User, - conan_module.PropertyRecipeChannel: rref.Channel, - } - if !ignoreRecipeRevision { - filter[conan_module.PropertyRecipeRevision] = rref.RevisionOrDefault() - } - if pref != nil { - filter[conan_module.PropertyPackageReference] = pref.Reference - if !ignorePackageRevision { - filter[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault() + err := db.WithTx(apictx, func(ctx std_ctx.Context) error { + pv, err := packages_model.GetVersionByNameAndVersion(ctx, apictx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version) + if err != nil { + return err } - } - pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{ - VersionID: pv.ID, - Properties: filter, + pd, err = packages_model.GetPackageDescriptor(ctx, pv) + if err != nil { + return err + } + + filter := map[string]string{ + conan_module.PropertyRecipeUser: rref.User, + conan_module.PropertyRecipeChannel: rref.Channel, + } + if !ignoreRecipeRevision { + filter[conan_module.PropertyRecipeRevision] = rref.RevisionOrDefault() + } + if pref != nil { + filter[conan_module.PropertyPackageReference] = pref.Reference + if !ignorePackageRevision { + filter[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault() + } + } + + pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{ + VersionID: pv.ID, + Properties: filter, + }) + if err != nil { + return err + } + if len(pfs) == 0 { + return conan_model.ErrPackageReferenceNotExist + } + + for _, pf := range pfs { + if err := packages_service.DeletePackageFile(ctx, pf); err != nil { + return err + } + } + has, err := packages_model.HasVersionFileReferences(ctx, pv.ID) + if err != nil { + return err + } + if !has { + versionDeleted = true + + return packages_service.DeletePackageVersionAndReferences(ctx, pv) + } + return nil }) if err != nil { return err } - if len(pfs) == 0 { - return conan_model.ErrPackageReferenceNotExist - } - - for _, pf := range pfs { - if err := packages_service.DeletePackageFile(ctx, pf); err != nil { - return err - } - } - - versionDeleted := false - has, err := packages_model.HasVersionFileReferences(ctx, pv.ID) - if err != nil { - return err - } - if !has { - versionDeleted = true - - if err := packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil { - return err - } - } - - if err := committer.Commit(); err != nil { - return err - } if versionDeleted { notification.NotifyPackageDelete(apictx, apictx.Doer, pd) diff --git a/routers/api/packages/container/blob.go b/routers/api/packages/container/blob.go index c8e8dd0545..f2d63297c1 100644 --- a/routers/api/packages/container/blob.go +++ b/routers/api/packages/container/blob.go @@ -26,19 +26,19 @@ var uploadVersionMutex sync.Mutex // saveAsPackageBlob creates a package blob from an upload // The uploaded blob gets stored in a special upload version to link them to the package/image -func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pci *packages_service.PackageCreationInfo) (*packages_model.PackageBlob, error) { +func saveAsPackageBlob(ctx context.Context, hsr packages_module.HashedSizeReader, pci *packages_service.PackageCreationInfo) (*packages_model.PackageBlob, error) { pb := packages_service.NewPackageBlob(hsr) exists := false contentStore := packages_module.NewContentStore() - uploadVersion, err := getOrCreateUploadVersion(&pci.PackageInfo) + uploadVersion, err := getOrCreateUploadVersion(ctx, &pci.PackageInfo) if err != nil { return nil, err } - err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { + err = db.WithTx(ctx, func(ctx context.Context) error { if err := packages_service.CheckSizeQuotaExceeded(ctx, pci.Creator, pci.Owner, packages_model.TypeContainer, hsr.Size()); err != nil { return err } @@ -79,24 +79,24 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pci *packages_servi } // mountBlob mounts the specific blob to a different package -func mountBlob(pi *packages_service.PackageInfo, pb *packages_model.PackageBlob) error { - uploadVersion, err := getOrCreateUploadVersion(pi) +func mountBlob(ctx context.Context, pi *packages_service.PackageInfo, pb *packages_model.PackageBlob) error { + uploadVersion, err := getOrCreateUploadVersion(ctx, pi) if err != nil { return err } - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { + return db.WithTx(ctx, func(ctx context.Context) error { return createFileForBlob(ctx, uploadVersion, pb) }) } -func getOrCreateUploadVersion(pi *packages_service.PackageInfo) (*packages_model.PackageVersion, error) { +func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageInfo) (*packages_model.PackageVersion, error) { var uploadVersion *packages_model.PackageVersion // FIXME: Replace usage of mutex with database transaction // https://github.com/go-gitea/gitea/pull/21862 uploadVersionMutex.Lock() - err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { + err := db.WithTx(ctx, func(ctx context.Context) error { created := true p := &packages_model.Package{ OwnerID: pi.Owner.ID, @@ -172,8 +172,8 @@ func createFileForBlob(ctx context.Context, pv *packages_model.PackageVersion, p return nil } -func deleteBlob(ownerID int64, image, digest string) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { +func deleteBlob(ctx context.Context, ownerID int64, image, digest string) error { + return db.WithTx(ctx, func(ctx context.Context) error { pfds, err := container_model.GetContainerBlobs(ctx, &container_model.BlobSearchOptions{ OwnerID: ownerID, Image: image, diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 8f79805cc8..7bd5cadaaf 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -210,7 +210,7 @@ func InitiateUploadBlob(ctx *context.Context) { } if accessible { - if err := mountBlob(&packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil { + if err := mountBlob(ctx, &packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } @@ -239,7 +239,7 @@ func InitiateUploadBlob(ctx *context.Context) { return } - if _, err := saveAsPackageBlob( + if _, err := saveAsPackageBlob(ctx, buf, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ @@ -384,7 +384,7 @@ func EndUploadBlob(ctx *context.Context) { return } - if _, err := saveAsPackageBlob( + if _, err := saveAsPackageBlob(ctx, uploader, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ @@ -502,7 +502,7 @@ func DeleteBlob(ctx *context.Context) { return } - if err := deleteBlob(ctx.Package.Owner.ID, ctx.Params("image"), d); err != nil { + if err := deleteBlob(ctx, ctx.Package.Owner.ID, ctx.Params("image"), d); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } @@ -543,7 +543,7 @@ func UploadManifest(ctx *context.Context) { return } - digest, err := processManifest(mci, buf) + digest, err := processManifest(ctx, mci, buf) if err != nil { var namedError *namedError if errors.As(err, &namedError) { diff --git a/routers/api/packages/container/manifest.go b/routers/api/packages/container/manifest.go index 1dbd058d6b..6678ed20bc 100644 --- a/routers/api/packages/container/manifest.go +++ b/routers/api/packages/container/manifest.go @@ -50,7 +50,7 @@ type manifestCreationInfo struct { Properties map[string]string } -func processManifest(mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) { +func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) { var index oci.Index if err := json.NewDecoder(buf).Decode(&index); err != nil { return "", err @@ -72,14 +72,14 @@ func processManifest(mci *manifestCreationInfo, buf *packages_module.HashedBuffe } if isImageManifestMediaType(mci.MediaType) { - return processImageManifest(mci, buf) + return processImageManifest(ctx, mci, buf) } else if isImageIndexMediaType(mci.MediaType) { - return processImageManifestIndex(mci, buf) + return processImageManifestIndex(ctx, mci, buf) } return "", errManifestInvalid } -func processImageManifest(mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) { +func processImageManifest(ctx context.Context, mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) { manifestDigest := "" err := func() error { @@ -92,7 +92,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -181,7 +181,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed return err } - if err := notifyPackageCreate(mci.Creator, pv); err != nil { + if err := notifyPackageCreate(ctx, mci.Creator, pv); err != nil { return err } @@ -196,7 +196,7 @@ func processImageManifest(mci *manifestCreationInfo, buf *packages_module.Hashed return manifestDigest, nil } -func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) { +func processImageManifestIndex(ctx context.Context, mci *manifestCreationInfo, buf *packages_module.HashedBuffer) (string, error) { manifestDigest := "" err := func() error { @@ -209,7 +209,7 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -285,7 +285,7 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H return err } - if err := notifyPackageCreate(mci.Creator, pv); err != nil { + if err := notifyPackageCreate(ctx, mci.Creator, pv); err != nil { return err } @@ -300,13 +300,13 @@ func processImageManifestIndex(mci *manifestCreationInfo, buf *packages_module.H return manifestDigest, nil } -func notifyPackageCreate(doer *user_model.User, pv *packages_model.PackageVersion) error { - pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv) +func notifyPackageCreate(ctx context.Context, doer *user_model.User, pv *packages_model.PackageVersion) error { + pd, err := packages_model.GetPackageDescriptor(ctx, pv) if err != nil { return err } - notification.NotifyPackageCreate(db.DefaultContext, doer, pd) + notification.NotifyPackageCreate(ctx, doer, pd) return nil } diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 3616211d61..d1e271f23f 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -5,6 +5,7 @@ package npm import ( "bytes" + std_ctx "context" "errors" "fmt" "io" @@ -222,7 +223,7 @@ func UploadPackage(ctx *context.Context) { } for _, tag := range npmPackage.DistTags { - if err := setPackageTag(tag, pv, false); err != nil { + if err := setPackageTag(ctx, tag, pv, false); err != nil { if err == errInvalidTagName { apiError(ctx, http.StatusBadRequest, err) return @@ -345,7 +346,7 @@ func AddPackageTag(ctx *context.Context) { return } - if err := setPackageTag(ctx.Params("tag"), pv, false); err != nil { + if err := setPackageTag(ctx, ctx.Params("tag"), pv, false); err != nil { if err == errInvalidTagName { apiError(ctx, http.StatusBadRequest, err) return @@ -366,7 +367,7 @@ func DeletePackageTag(ctx *context.Context) { } if len(pvs) != 0 { - if err := setPackageTag(ctx.Params("tag"), pvs[0], true); err != nil { + if err := setPackageTag(ctx, ctx.Params("tag"), pvs[0], true); err != nil { if err == errInvalidTagName { apiError(ctx, http.StatusBadRequest, err) return @@ -377,7 +378,7 @@ func DeletePackageTag(ctx *context.Context) { } } -func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly bool) error { +func setPackageTag(ctx std_ctx.Context, tag string, pv *packages_model.PackageVersion, deleteOnly bool) error { if tag == "" { return errInvalidTagName } @@ -386,47 +387,42 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo return errInvalidTagName } - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - - pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ - PackageID: pv.PackageID, - Properties: map[string]string{ - npm_module.TagProperty: tag, - }, - IsInternal: util.OptionalBoolFalse, - }) - if err != nil { - return err - } - - if len(pvs) == 1 { - pvps, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeVersion, pvs[0].ID, npm_module.TagProperty) + return db.WithTx(ctx, func(ctx std_ctx.Context) error { + pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ + PackageID: pv.PackageID, + Properties: map[string]string{ + npm_module.TagProperty: tag, + }, + IsInternal: util.OptionalBoolFalse, + }) if err != nil { return err } - for _, pvp := range pvps { - if pvp.Value == tag { - if err := packages_model.DeletePropertyByID(ctx, pvp.ID); err != nil { - return err + if len(pvs) == 1 { + pvps, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeVersion, pvs[0].ID, npm_module.TagProperty) + if err != nil { + return err + } + + for _, pvp := range pvps { + if pvp.Value == tag { + if err := packages_model.DeletePropertyByID(ctx, pvp.ID); err != nil { + return err + } + break } - break } } - } - if !deleteOnly { - _, err = packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, npm_module.TagProperty, tag) - if err != nil { - return err + if !deleteOnly { + _, err = packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, npm_module.TagProperty, tag) + if err != nil { + return err + } } - } - - return committer.Commit() + return nil + }) } func PackageSearch(ctx *context.Context) { diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index f90c65817d..6c04d0943a 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -8,7 +8,6 @@ import ( "net/http" asymkey_model "code.gitea.io/gitea/models/asymkey" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -31,7 +30,7 @@ func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *a if defaultUser.ID == key.OwnerID { apiKey.Owner = convert.ToUser(ctx, defaultUser, defaultUser) } else { - user, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID) + user, err := user_model.GetUserByID(ctx, key.OwnerID) if err != nil { return apiKey, err } diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index ace54fc0d8..731a1d6ac2 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -85,7 +85,7 @@ func Packages(ctx *context.Context) { // DeletePackageVersion deletes a package version func DeletePackageVersion(ctx *context.Context) { - pv, err := packages_model.GetVersionByID(db.DefaultContext, ctx.FormInt64("id")) + pv, err := packages_model.GetVersionByID(ctx, ctx.FormInt64("id")) if err != nil { ctx.ServerError("GetRepositoryByID", err) return diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go index e11dd2aca2..ecb73a928f 100644 --- a/routers/web/healthcheck/check.go +++ b/routers/web/healthcheck/check.go @@ -4,6 +4,7 @@ package healthcheck import ( + "context" "net/http" "os" "time" @@ -72,7 +73,7 @@ func Check(w http.ResponseWriter, r *http.Request) { statuses := make([]status, 0) if setting.InstallLock { - statuses = append(statuses, checkDatabase(rsp.Checks)) + statuses = append(statuses, checkDatabase(r.Context(), rsp.Checks)) statuses = append(statuses, checkCache(rsp.Checks)) } for _, s := range statuses { @@ -89,9 +90,9 @@ func Check(w http.ResponseWriter, r *http.Request) { } // database checks gitea database status -func checkDatabase(checks checks) status { +func checkDatabase(ctx context.Context, checks checks) status { st := componentStatus{} - if err := db.GetEngine(db.DefaultContext).Ping(); err != nil { + if err := db.GetEngine(ctx).Ping(); err != nil { st.Status = fail st.Time = getCheckTime() log.Error("database ping failed with error: %v", err) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index a1c82f5395..221c1f4c4f 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -198,7 +198,7 @@ type fileInfo struct { st typesniffer.SniffedType } -func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileInfo, error) { +func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileInfo, error) { dataRc, err := blob.DataAsync() if err != nil { return nil, nil, nil, err @@ -221,7 +221,7 @@ func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileIn return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil } - meta, err := git_model.GetLFSMetaObjectByOid(db.DefaultContext, repoID, pointer.Oid) + meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid) if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil } @@ -265,7 +265,7 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr ctx.Data["ReadmeExist"] = true ctx.Data["FileIsSymlink"] = readmeFile.IsLink() - buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, target.Blob()) + buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, target.Blob()) if err != nil { ctx.ServerError("getFileReader", err) return @@ -328,7 +328,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsViewFile"] = true ctx.Data["HideRepoInfo"] = true blob := entry.Blob() - buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, blob) + buf, dataRc, fInfo, err := getFileReader(ctx, ctx.Repo.Repository.ID, blob) if err != nil { ctx.ServerError("getFileReader", err) return From f2138d6968a96721f58655196ab4f132c20f9425 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Sun, 23 Jul 2023 23:13:41 -0500 Subject: [PATCH 05/11] Replace gogs/cron with go-co-op/gocron (#25977) Replace `github.com/gogs/cron` with `github.com/go-co-op/gocron` as the former package is not maintained for many years. --------- Co-authored-by: delvh --- assets/go-licenses.json | 15 ++++++--- go.mod | 3 +- go.sum | 10 ++++-- services/cron/cron.go | 34 +++++++++++++-------- services/cron/tasks.go | 22 +++++++++++-- services/cron/tasks_test.go | 61 +++++++++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 services/cron/tasks_test.go diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 384a57cf47..3a0da33a0a 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -409,6 +409,11 @@ "path": "github.com/go-chi/cors/LICENSE", "licenseText": "Copyright (c) 2014 Olivier Poitrey \u003crs@dailymotion.com\u003e\nCopyright (c) 2016-Present https://github.com/go-chi authors\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, + { + "name": "github.com/go-co-op/gocron", + "path": "github.com/go-co-op/gocron/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2014, 辣椒面\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/go-enry/go-enry/v2", "path": "github.com/go-enry/go-enry/v2/LICENSE", @@ -484,11 +489,6 @@ "path": "github.com/gogs/chardet/LICENSE", "licenseText": "Copyright (c) 2012 chardet Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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\nPartial of the Software is derived from ICU project. See icu-license.html for\nlicense of the derivative portions.\n" }, - { - "name": "github.com/gogs/cron", - "path": "github.com/gogs/cron/LICENSE", - "licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" - }, { "name": "github.com/gogs/go-gogs-client", "path": "github.com/gogs/go-gogs-client/LICENSE", @@ -909,6 +909,11 @@ "path": "github.com/robfig/cron/LICENSE", "licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, + { + "name": "github.com/robfig/cron/v3", + "path": "github.com/robfig/cron/v3/LICENSE", + "licenseText": "Copyright (C) 2012 Rob Figueiredo\nAll Rights Reserved.\n\nMIT LICENSE\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" + }, { "name": "github.com/rs/xid", "path": "github.com/rs/xid/LICENSE", diff --git a/go.mod b/go.mod index 29a17b16ab..9038bdd689 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 + github.com/go-co-op/gocron v1.30.1 github.com/go-enry/go-enry/v2 v2.8.4 github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e github.com/go-git/go-billy/v5 v5.4.1 @@ -52,7 +53,6 @@ require ( github.com/go-webauthn/webauthn v0.8.6 github.com/gobwas/glob v0.2.3 github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f - github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-github/v53 v53.2.0 @@ -253,6 +253,7 @@ require ( github.com/rhysd/actionlint v1.6.25 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron v1.2.0 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/xid v1.5.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index 9c6250c101..976c0ead38 100644 --- a/go.sum +++ b/go.sum @@ -371,6 +371,8 @@ github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-co-op/gocron v1.30.1 h1:tjWUvJl5KrcwpkEkSXFSQFr4F9h5SfV/m4+RX0cV2fs= +github.com/go-co-op/gocron v1.30.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y= github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs= github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= @@ -496,8 +498,6 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= -github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8= -github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0= github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -787,6 +787,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -1038,10 +1039,14 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= @@ -1250,6 +1255,7 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= diff --git a/services/cron/cron.go b/services/cron/cron.go index 72deb94ceb..e3f31d08f0 100644 --- a/services/cron/cron.go +++ b/services/cron/cron.go @@ -14,10 +14,10 @@ import ( "code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/translation" - "github.com/gogs/cron" + "github.com/go-co-op/gocron" ) -var c = cron.New() +var scheduler = gocron.NewScheduler(time.Local) // Prevent duplicate running tasks. var taskStatusTable = sync.NewStatusTable() @@ -39,11 +39,11 @@ func NewContext(original context.Context) { } } - c.Start() + scheduler.StartAsync() started = true lock.Unlock() graceful.GetManager().RunAtShutdown(context.Background(), func() { - c.Stop() + scheduler.Stop() lock.Lock() started = false lock.Unlock() @@ -77,13 +77,20 @@ type TaskTable []*TaskTableRow // ListTasks returns all running cron tasks. func ListTasks() TaskTable { - entries := c.Entries() - eMap := map[string]*cron.Entry{} - for _, e := range entries { - eMap[e.Description] = e + jobs := scheduler.Jobs() + jobMap := map[string]*gocron.Job{} + for _, job := range jobs { + // the first tag is the task name + tags := job.Tags() + if len(tags) == 0 { // should never happen + continue + } + jobMap[job.Tags()[0]] = job } + lock.Lock() defer lock.Unlock() + tTable := make([]*TaskTableRow, 0, len(tasks)) for _, task := range tasks { spec := "-" @@ -91,10 +98,13 @@ func ListTasks() TaskTable { next time.Time prev time.Time ) - if e, ok := eMap[task.Name]; ok { - spec = e.Spec - next = e.Next - prev = e.Prev + if e, ok := jobMap[task.Name]; ok { + tags := e.Tags() + if len(tags) > 1 { + spec = tags[1] // the second tag is the task spec + } + next = e.NextRun() + prev = e.PreviousRun() } task.lock.Lock() tTable = append(tTable, &TaskTableRow{ diff --git a/services/cron/tasks.go b/services/cron/tasks.go index 1c5493c898..ea1925c26c 100644 --- a/services/cron/tasks.go +++ b/services/cron/tasks.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "reflect" + "strings" "sync" "code.gitea.io/gitea/models/db" @@ -176,8 +177,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo if config.IsEnabled() { // We cannot use the entry return as there is no way to lock it - if _, err = c.AddJob(name, config.GetSchedule(), task); err != nil { - log.Error("Unable to register cron task with name: %s Error: %v", name, err) + if err := addTaskToScheduler(task); err != nil { return err } } @@ -199,3 +199,21 @@ func RegisterTaskFatal(name string, config Config, fun func(context.Context, *us log.Fatal("Unable to register cron task %s Error: %v", name, err) } } + +func addTaskToScheduler(task *Task) error { + tags := []string{task.Name, task.config.GetSchedule()} // name and schedule can't be get from job, so we add them as tag + if scheduleHasSeconds(task.config.GetSchedule()) { + scheduler = scheduler.CronWithSeconds(task.config.GetSchedule()) + } else { + scheduler = scheduler.Cron(task.config.GetSchedule()) + } + if _, err := scheduler.Tag(tags...).Do(task.Run); err != nil { + log.Error("Unable to register cron task with name: %s Error: %v", task.Name, err) + return err + } + return nil +} + +func scheduleHasSeconds(schedule string) bool { + return len(strings.Fields(schedule)) >= 6 +} diff --git a/services/cron/tasks_test.go b/services/cron/tasks_test.go new file mode 100644 index 0000000000..69052d739c --- /dev/null +++ b/services/cron/tasks_test.go @@ -0,0 +1,61 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cron + +import ( + "strconv" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddTaskToScheduler(t *testing.T) { + assert.Len(t, scheduler.Jobs(), 0) + defer scheduler.Clear() + + // no seconds + err := addTaskToScheduler(&Task{ + Name: "task 1", + config: &BaseConfig{ + Schedule: "5 4 * * *", + }, + }) + assert.NoError(t, err) + assert.Len(t, scheduler.Jobs(), 1) + assert.Equal(t, "task 1", scheduler.Jobs()[0].Tags()[0]) + assert.Equal(t, "5 4 * * *", scheduler.Jobs()[0].Tags()[1]) + + // with seconds + err = addTaskToScheduler(&Task{ + Name: "task 2", + config: &BaseConfig{ + Schedule: "30 5 4 * * *", + }, + }) + assert.NoError(t, err) + assert.Len(t, scheduler.Jobs(), 2) + assert.Equal(t, "task 2", scheduler.Jobs()[1].Tags()[0]) + assert.Equal(t, "30 5 4 * * *", scheduler.Jobs()[1].Tags()[1]) +} + +func TestScheduleHasSeconds(t *testing.T) { + tests := []struct { + schedule string + hasSecond bool + }{ + {"* * * * * *", true}, + {"* * * * *", false}, + {"5 4 * * *", false}, + {"5 4 * * *", false}, + {"5,8 4 * * *", false}, + {"* * * * * *", true}, + {"5,8 4 * * *", false}, + } + + for i, test := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + assert.Equal(t, test.hasSecond, scheduleHasSeconds(test.schedule)) + }) + } +} From 4b6764bbb36f616035477480fc14959687d9d65b Mon Sep 17 00:00:00 2001 From: "Panagiotis \"Ivory\" Vasilopoulos" Date: Mon, 24 Jul 2023 04:17:32 +0000 Subject: [PATCH 06/11] Make organization redirect warning more clear (#26077) --- options/locale/locale_en-US.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 24be7e0fc3..8784ab6878 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -640,7 +640,7 @@ update_language_success = Language has been updated. update_profile_success = Your profile has been updated. change_username = Your username has been changed. change_username_prompt = Note: username changes also change your account URL. -change_username_redirect_prompt = The old username will redirect until it is claimed. +change_username_redirect_prompt = The old username will redirect until someone claims it. continue = Continue cancel = Cancel language = Language @@ -2545,7 +2545,7 @@ settings.visibility.private_shortname = Private settings.update_settings = Update Settings settings.update_setting_success = Organization settings have been updated. -settings.change_orgname_prompt = Note: changing the organization name also changes the organization's URL. +settings.change_orgname_prompt = Note: Changing the organization name will also change your organization's URL and free the old name. settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed. settings.update_avatar_success = The organization's avatar has been updated. settings.delete = Delete Organization From 674df05b16f396bf6f2a952923b9c2dfe371415b Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jul 2023 12:57:21 +0800 Subject: [PATCH 07/11] Use stderr as fallback if the log file can't be opened (#26074) If the log file can't be opened, what should it do? panic/exit? ignore logs? fallback to stderr? It seems that "fallback to stderr" is slightly better than others .... --- modules/log/event_writer_file.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/log/event_writer_file.go b/modules/log/event_writer_file.go index 4f41b96453..fd73d7d30a 100644 --- a/modules/log/event_writer_file.go +++ b/modules/log/event_writer_file.go @@ -4,6 +4,8 @@ package log import ( + "io" + "code.gitea.io/gitea/modules/util/rotatingfilewriter" ) @@ -19,7 +21,7 @@ type WriterFileOption struct { type eventWriterFile struct { *EventWriterBaseImpl - fileWriter *rotatingfilewriter.RotatingFileWriter + fileWriter io.WriteCloser } var _ EventWriter = (*eventWriterFile)(nil) @@ -37,7 +39,10 @@ func NewEventWriterFile(name string, mode WriterMode) EventWriter { CompressionLevel: opt.CompressionLevel, }) if err != nil { + // if the log file can't be opened, what should it do? panic/exit? ignore logs? fallback to stderr? + // it seems that "fallback to stderr" is slightly better than others .... FallbackErrorf("unable to open log file %q: %v", opt.FileName, err) + w.fileWriter = nopCloser{Writer: LoggerToWriter(FallbackErrorf)} } w.OutputWriteCloser = w.fileWriter return w From f5c7d4cfddfe7fc615199a7438749ed79c40361f Mon Sep 17 00:00:00 2001 From: sillyguodong <33891828+sillyguodong@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:11:27 +0800 Subject: [PATCH 08/11] Reduce unnecessary DB queries for Actions tasks (#25199) Close #24544 Changes: - Create `action_tasks_version` table to store the latest version of each scope (global, org and repo). - When a job with the status of `waiting` is created, the tasks version of the scopes it belongs to will increase. - When the status of a job already in the database is updated to `waiting`, the tasks version of the scopes it belongs to will increase. - On Gitea side, in `FeatchTask()`, will try to query the `action_tasks_version` record of the scope of the runner that call `FetchTask()`. If the record does not exist, will insert a row. Then, Gitea will compare the version passed from runner to Gitea with the version in database, if inconsistent, try pick task. Gitea always returns the latest version from database to the runner. Related: - Protocol: https://gitea.com/gitea/actions-proto-def/pulls/10 - Runner: https://gitea.com/gitea/act_runner/pulls/219 --- models/actions/run.go | 10 +++ models/actions/run_job.go | 7 ++ models/actions/task.go | 3 +- models/actions/tasks_version.go | 105 +++++++++++++++++++++++++++ models/migrations/migrations.go | 2 + models/migrations/v1_21/v267.go | 23 ++++++ routers/api/actions/runner/runner.go | 33 +++++++-- 7 files changed, 174 insertions(+), 9 deletions(-) create mode 100644 models/actions/tasks_version.go create mode 100644 models/migrations/v1_21/v267.go diff --git a/models/actions/run.go b/models/actions/run.go index 7b62ff884f..5396c612f6 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -195,6 +195,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork } runJobs := make([]*ActionRunJob, 0, len(jobs)) + var hasWaiting bool for _, v := range jobs { id, job := v.Job() needs := job.Needs() @@ -205,6 +206,8 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork status := StatusWaiting if len(needs) > 0 || run.NeedApproval { status = StatusBlocked + } else { + hasWaiting = true } job.Name, _ = util.SplitStringAtByteN(job.Name, 255) runJobs = append(runJobs, &ActionRunJob{ @@ -225,6 +228,13 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork return err } + // if there is a job in the waiting status, increase tasks version. + if hasWaiting { + if err := IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil { + return err + } + } + return commiter.Commit() } diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 0002e50770..c7620cd8bc 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -111,6 +111,13 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col return affected, nil } + if affected != 0 && util.SliceContains(cols, "status") && job.Status.IsWaiting() { + // if the status of job changes to waiting again, increase tasks version. + if err := IncreaseTaskVersion(ctx, job.OwnerID, job.RepoID); err != nil { + return affected, err + } + } + if job.RunID == 0 { var err error if job, err = GetRunJobByID(ctx, job.ID); err != nil { diff --git a/models/actions/task.go b/models/actions/task.go index 55044ec82d..9cc0fd0df8 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -215,12 +215,11 @@ func GetRunningTaskByToken(ctx context.Context, token string) (*ActionTask, erro } func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask, bool, error) { - dbCtx, commiter, err := db.TxContext(ctx) + ctx, commiter, err := db.TxContext(ctx) if err != nil { return nil, false, err } defer commiter.Close() - ctx = dbCtx.WithContext(ctx) e := db.GetEngine(ctx) diff --git a/models/actions/tasks_version.go b/models/actions/tasks_version.go new file mode 100644 index 0000000000..5c0a86538d --- /dev/null +++ b/models/actions/tasks_version.go @@ -0,0 +1,105 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "context" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" +) + +// ActionTasksVersion +// If both ownerID and repoID is zero, its scope is global. +// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currrently). +// If ownerID is zero and repoID is not zero, its scope is repo. +type ActionTasksVersion struct { + ID int64 `xorm:"pk autoincr"` + OwnerID int64 `xorm:"UNIQUE(owner_repo)"` + RepoID int64 `xorm:"INDEX UNIQUE(owner_repo)"` + Version int64 + CreatedUnix timeutil.TimeStamp `xorm:"created"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated"` +} + +func init() { + db.RegisterModel(new(ActionTasksVersion)) +} + +func GetTasksVersionByScope(ctx context.Context, ownerID, repoID int64) (int64, error) { + var tasksVersion ActionTasksVersion + has, err := db.GetEngine(ctx).Where("owner_id = ? AND repo_id = ?", ownerID, repoID).Get(&tasksVersion) + if err != nil { + return 0, err + } else if !has { + return 0, nil + } + return tasksVersion.Version, err +} + +func insertTasksVersion(ctx context.Context, ownerID, repoID int64) (*ActionTasksVersion, error) { + tasksVersion := &ActionTasksVersion{ + OwnerID: ownerID, + RepoID: repoID, + Version: 1, + } + if _, err := db.GetEngine(ctx).Insert(tasksVersion); err != nil { + return nil, err + } + return tasksVersion, nil +} + +func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) error { + result, err := db.GetEngine(ctx).Exec("UPDATE action_tasks_version SET version = version + 1 WHERE owner_id = ? AND repo_id = ?", ownerID, repoID) + if err != nil { + return err + } + affected, err := result.RowsAffected() + if err != nil { + return err + } + + if affected == 0 { + // if update sql does not affect any rows, the database may be broken, + // so re-insert the row of version data here. + if _, err := insertTasksVersion(ctx, ownerID, repoID); err != nil { + return err + } + } + + return nil +} + +func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error { + ctx, commiter, err := db.TxContext(ctx) + if err != nil { + return err + } + defer commiter.Close() + + // 1. increase global + if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil { + log.Error("IncreaseTasksVersionByScope(Global): %v", err) + return err + } + + // 2. increase owner + if ownerID > 0 { + if err := increaseTasksVersionByScope(ctx, ownerID, 0); err != nil { + log.Error("IncreaseTasksVersionByScope(Owner): %v", err) + return err + } + } + + // 3. increase repo + if repoID > 0 { + if err := increaseTasksVersionByScope(ctx, 0, repoID); err != nil { + log.Error("IncreaseTasksVersionByScope(Repo): %v", err) + return err + } + } + + return commiter.Commit() +} diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 6599cb9cda..bfe4b56cd1 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -515,6 +515,8 @@ var migrations = []Migration{ NewMigration("Alter Actions Artifact table", v1_21.AlterActionArtifactTable), // v266 -> v267 NewMigration("Reduce commit status", v1_21.ReduceCommitStatus), + // v267 -> v268 + NewMigration("Add action_tasks_version table", v1_21.CreateActionTasksVersionTable), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_21/v267.go b/models/migrations/v1_21/v267.go new file mode 100644 index 0000000000..bc0e954bdc --- /dev/null +++ b/models/migrations/v1_21/v267.go @@ -0,0 +1,23 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" +) + +func CreateActionTasksVersionTable(x *xorm.Engine) error { + type ActionTasksVersion struct { + ID int64 `xorm:"pk autoincr"` + OwnerID int64 `xorm:"UNIQUE(owner_repo)"` + RepoID int64 `xorm:"INDEX UNIQUE(owner_repo)"` + Version int64 + CreatedUnix timeutil.TimeStamp `xorm:"created"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated"` + } + + return x.Sync(new(ActionTasksVersion)) +} diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go index 17801cb322..6de5964cb7 100644 --- a/routers/api/actions/runner/runner.go +++ b/routers/api/actions/runner/runner.go @@ -127,20 +127,39 @@ func (s *Service) Declare( // FetchTask assigns a task to the runner func (s *Service) FetchTask( ctx context.Context, - _ *connect.Request[runnerv1.FetchTaskRequest], + req *connect.Request[runnerv1.FetchTaskRequest], ) (*connect.Response[runnerv1.FetchTaskResponse], error) { runner := GetRunner(ctx) var task *runnerv1.Task - if t, ok, err := pickTask(ctx, runner); err != nil { - log.Error("pick task failed: %v", err) - return nil, status.Errorf(codes.Internal, "pick task: %v", err) - } else if ok { - task = t + tasksVersion := req.Msg.TasksVersion // task version from runner + latestVersion, err := actions_model.GetTasksVersionByScope(ctx, runner.OwnerID, runner.RepoID) + if err != nil { + return nil, status.Errorf(codes.Internal, "query tasks version failed: %v", err) + } else if latestVersion == 0 { + if err := actions_model.IncreaseTaskVersion(ctx, runner.OwnerID, runner.RepoID); err != nil { + return nil, status.Errorf(codes.Internal, "fail to increase task version: %v", err) + } + // if we don't increase the value of `latestVersion` here, + // the response of FetchTask will return tasksVersion as zero. + // and the runner will treat it as an old version of Gitea. + latestVersion++ } + if tasksVersion != latestVersion { + // if the task version in request is not equal to the version in db, + // it means there may still be some tasks not be assgined. + // try to pick a task for the runner that send the request. + if t, ok, err := pickTask(ctx, runner); err != nil { + log.Error("pick task failed: %v", err) + return nil, status.Errorf(codes.Internal, "pick task: %v", err) + } else if ok { + task = t + } + } res := connect.NewResponse(&runnerv1.FetchTaskResponse{ - Task: task, + Task: task, + TasksVersion: latestVersion, }) return res, nil } From 478f36a53891bac457fa3f9baebae8a6232be1f6 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jul 2023 14:49:18 +0800 Subject: [PATCH 09/11] Add missing default value for some Bool cli flags (#26082) In #25959 I forgot to add default values to some Bool flags (which were BoolT in cli/v1, BoolT means default to be true) This PR adds the default "Value" for them. ``` ./cmd/manager_logging.go: }, cli.BoolTFlag{ ./cmd/manager_logging.go- Name: "rotate, r", ./cmd/manager_logging.go- Usage: "Rotate logs", -- ./cmd/manager_logging.go: }, cli.BoolTFlag{ ./cmd/manager_logging.go- Name: "daily, d", ./cmd/manager_logging.go- Usage: "Rotate logs daily", -- ./cmd/manager_logging.go: }, cli.BoolTFlag{ ./cmd/manager_logging.go- Name: "compress, z", ./cmd/manager_logging.go- Usage: "Compress rotated logs", -- ./cmd/admin.go: cli.BoolTFlag{ ./cmd/admin.go- Name: "force-smtps", ./cmd/admin.go- Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", -- ./cmd/admin.go: cli.BoolTFlag{ ./cmd/admin.go- Name: "skip-verify", ./cmd/admin.go- Usage: "Skip TLS verify.", -- ./cmd/admin.go: cli.BoolTFlag{ ./cmd/admin.go- Name: "disable-helo", ./cmd/admin.go- Usage: "Disable SMTP helo.", -- ./cmd/admin.go: cli.BoolTFlag{ ./cmd/admin.go- Name: "skip-local-2fa", ./cmd/admin.go- Usage: "Skip 2FA to log on.", -- ./cmd/admin.go: cli.BoolTFlag{ ./cmd/admin.go- Name: "active", ./cmd/admin.go- Usage: "This Authentication Source is Activated.", ``` --- cmd/admin.go | 5 +++++ cmd/manager_logging.go | 3 +++ 2 files changed, 8 insertions(+) diff --git a/cmd/admin.go b/cmd/admin.go index ea62075093..745427ca24 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -298,10 +298,12 @@ var ( &cli.BoolFlag{ Name: "force-smtps", Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", + Value: true, }, &cli.BoolFlag{ Name: "skip-verify", Usage: "Skip TLS verify.", + Value: true, }, &cli.StringFlag{ Name: "helo-hostname", @@ -311,6 +313,7 @@ var ( &cli.BoolFlag{ Name: "disable-helo", Usage: "Disable SMTP helo.", + Value: true, }, &cli.StringFlag{ Name: "allowed-domains", @@ -320,10 +323,12 @@ var ( &cli.BoolFlag{ Name: "skip-local-2fa", Usage: "Skip 2FA to log on.", + Value: true, }, &cli.BoolFlag{ Name: "active", Usage: "This Authentication Source is Activated.", + Value: true, }, } diff --git a/cmd/manager_logging.go b/cmd/manager_logging.go index 84c962561e..7d34fc9ac2 100644 --- a/cmd/manager_logging.go +++ b/cmd/manager_logging.go @@ -117,6 +117,7 @@ var ( Name: "rotate", Aliases: []string{"r"}, Usage: "Rotate logs", + Value: true, }, &cli.Int64Flag{ Name: "max-size", @@ -127,6 +128,7 @@ var ( Name: "daily", Aliases: []string{"d"}, Usage: "Rotate logs daily", + Value: true, }, &cli.IntFlag{ Name: "max-days", @@ -137,6 +139,7 @@ var ( Name: "compress", Aliases: []string{"z"}, Usage: "Compress rotated logs", + Value: true, }, &cli.IntFlag{ Name: "compression-level", From cdd3d4b8d8814137e16116002e5bf6aad38b794f Mon Sep 17 00:00:00 2001 From: idk Date: Mon, 24 Jul 2023 03:18:17 -0400 Subject: [PATCH 10/11] Allow the use of alternative net.Listener implementations by downstreams (#25855) This is a simple PR which moves the `GetListener` function to a `DefaultGetListener` function, and changes `GetListener` to be a variable which by default points to the `DefaultGetListener` function. This allows people who may exist quasi-downstream of Gitea to create alternate "GetListener" functions, with identical signatures, which return different implementations of the `net.Listener` interface. This approach is expressly intended to be non-invasive and have the least possible impact on the gitea codebase. A previous version of this idea was rejected before: https://github.com/go-gitea/gitea/issues/15544 but because of issues like: https://github.com/go-gitea/gitea/issues/22335 I **really** think that recommending people configure proxies by hand is exactly the wrong way to do things(This is why there is a Tor Browser.). This tiny change lets me put proper hidden service configuration into single `i2p.go` file which lives in `modules/graceful/` and which never has to be checked in to your codebase or affect your dependencies or bloat your project in any way, it can live on a branch in my fork and I'll fast-forward every release and never the twain shall meet. The main use-case for this is to listen on Peer-to-Peer networks and Hidden Services directly without error-prone and cumbersome port-forwarding configuration. For instance, I might implement an "I2PGetListener" as follows: ```Go // adapted from i2p.go which is unchecked-in in my modules/graceful/ directory import "github.com/eyedeekay/onramp" var garlic = &onramp.Garlic{} func I2PGetListener(network, address string) (net.Listener, error) { // Add a deferral to say that we've tried to grab a listener defer GetManager().InformCleanup() switch network { case "tcp", "tcp4", "tcp6", "i2p", "i2pt": return garlic.Listen() case "unix", "unixpacket": // I2P isn't really a replacement for the stuff you use Unix sockets for and it's also not an anonymity risk, so treat them normally unixAddr, err := net.ResolveUnixAddr(network, address) if err != nil { return nil, err } return GetListenerUnix(network, unixAddr) default: return nil, net.UnknownNetworkError(network) } } ``` I could then substitute that GetListener function and be 50% of the way to having a fully-functioning gitea-over-hidden-services instance without any additional configuration(The other 50% doesn't require any code-changes on gitea's part). There are 2 advantages here, one being convenience, first this turns hidden services into a zero-configuration option for self-hosting gitea, and second safety, these Go libraries are passing around hidden-service-only versions of the net.Addr struct, they're using hidden-service-only versions of the sockets, which are both expressly designed to never require access to any information outside the hidden service network, manipulating the application so it reveals information about the host becomes much more difficult, and some attacks become nearly impossible. It also opens up TLS-over-Hidden Services support which is niche right now, of course, but in a future where gitea instances federate if hidden services want to be part of the federation they're probably going to need TLS certificates. They don't need to be painful to set up. This doesn't fix an open issue, but it might affect: - https://github.com/go-gitea/gitea/issues/22335 - my `i2p.go` file actually has a mod that fixes this but it requires adding a handful of new dependencies to gitea and isn't compatible with the normal way you guys recommend using a proxy so I don't think it's ready to send to you as a PR, but if I can find a non-invasive way to fix it I will. - https://github.com/go-gitea/gitea/issues/18240 I hereby agree to the Code of Conduct published here: https://github.com/go-gitea/gitea/blob/8b89563bf1031089a218e6d05dc61047281b35ee/CODE_OF_CONDUCT.md I have read and understood the recommendations published here: https://github.com/go-gitea/gitea/blob/8b89563bf1031089a218e6d05dc61047281b35ee/CONTRIBUTING.md Thank you for your consideration. --------- Co-authored-by: eyedeekay Co-authored-by: wxiaoguang --- modules/graceful/net_unix.go | 8 +++++--- modules/graceful/net_windows.go | 8 +++++--- modules/graceful/server.go | 8 ++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/modules/graceful/net_unix.go b/modules/graceful/net_unix.go index e9c1285123..f5af1e3937 100644 --- a/modules/graceful/net_unix.go +++ b/modules/graceful/net_unix.go @@ -150,11 +150,13 @@ func CloseProvidedListeners() error { return returnableError } -// GetListener obtains a listener for the local network address. The network must be +// DefaultGetListener obtains a listener for the local network address. The network must be // a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It // returns an provided net.Listener for the matching network and address, or -// creates a new one using net.Listen. -func GetListener(network, address string) (net.Listener, error) { +// creates a new one using net.Listen. This function can be replaced by changing the +// GetListener variable at the top of this file, for example to listen on an onion service using +// github.com/cretz/bine +func DefaultGetListener(network, address string) (net.Listener, error) { // Add a deferral to say that we've tried to grab a listener defer GetManager().InformCleanup() switch network { diff --git a/modules/graceful/net_windows.go b/modules/graceful/net_windows.go index a2f58e224a..15d228d6b6 100644 --- a/modules/graceful/net_windows.go +++ b/modules/graceful/net_windows.go @@ -9,9 +9,11 @@ package graceful import "net" -// GetListener obtains a listener for the local network address. -// On windows this is basically just a shim around net.Listen. -func GetListener(network, address string) (net.Listener, error) { +// DefaultGetListener obtains a listener for the local network address. +// On windows this is basically just a shim around net.Listen. This function +// can be replaced by changing the GetListener variable at the top of this file, +// for example to listen on an onion service using github.com/cretz/bine +func DefaultGetListener(network, address string) (net.Listener, error) { // Add a deferral to say that we've tried to grab a listener defer GetManager().InformCleanup() diff --git a/modules/graceful/server.go b/modules/graceful/server.go index e42d35cd49..bd917828bc 100644 --- a/modules/graceful/server.go +++ b/modules/graceful/server.go @@ -33,6 +33,14 @@ var ( PerWriteWriteTimeoutKbTime = 10 * time.Second ) +// GetListener returns a listener from a GetListener function, which must have the +// signature: `func FunctioName(network, address string) (net.Listener, error)`. +// This determines the implementation of net.Listener which the server will use.` +// It is implemented in this way so that downstreams may specify the type of listener +// they want to provide Gitea on by default, such as with a hidden service or a p2p network +// No need to worry about "breaking" if there would be a refactoring for the Listeners. No compatibility-guarantee for this mechanism +var GetListener = DefaultGetListener + func init() { DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB) } From 4211efe8b7a0b38420da5c5d4f287a8d466aedc2 Mon Sep 17 00:00:00 2001 From: caicandong <50507092+CaiCandong@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:48:44 +0800 Subject: [PATCH 11/11] fix Missing 404 swagger response docs for /admin/users/{username} (#26086) close #26079 --- routers/api/v1/admin/user.go | 2 ++ templates/swagger/v1_json.tmpl | 3 +++ 2 files changed, 5 insertions(+) diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index c3af5dc90a..4f1e9a3f53 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -312,6 +312,8 @@ func DeleteUser(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "403": // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 7b3a616740..69874bdc75 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -620,6 +620,9 @@ "403": { "$ref": "#/responses/forbidden" }, + "404": { + "$ref": "#/responses/notFound" + }, "422": { "$ref": "#/responses/validationError" }