From a12a5f3652c339b17b187ff424a480631a3c1e1e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 23 Jul 2023 17:56:43 +0800 Subject: [PATCH 1/6] 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 2/6] [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 3/6] 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 4/6] 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 5/6] 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 6/6] 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