From 4567a3a1ad0490d9077102e0e7b5de35790e5803 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Wed, 24 Jan 2024 04:02:04 +0100 Subject: [PATCH] Allow to sync tags from admin dashboard (#28045) Inspired by #28043 This PR adds a option to the Admin Dashboard to sync all tags to the database. ![grafik](https://github.com/go-gitea/gitea/assets/15185051/26ac51ef-82a4-4fd9-a6a6-5aefec612ff6) --- modules/repository/repo.go | 16 +++++++++ options/locale/locale_en-US.ini | 2 ++ routers/init.go | 3 ++ routers/web/admin/admin.go | 8 +++++ services/release/release.go | 6 ++++ services/release/tag.go | 61 +++++++++++++++++++++++++++++++++ templates/admin/dashboard.tmpl | 4 +++ 7 files changed, 100 insertions(+) create mode 100644 services/release/tag.go diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 33363e4689bd1..5af69763d152e 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -284,6 +284,22 @@ func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo return repo, UpdateRepository(ctx, repo, false) } +// SyncRepoTags synchronizes releases table with repository tags +func SyncRepoTags(ctx context.Context, repoID int64) error { + repo, err := repo_model.GetRepositoryByID(ctx, repoID) + if err != nil { + return err + } + + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + return err + } + defer gitRepo.Close() + + return SyncReleasesWithTags(ctx, repo, gitRepo) +} + // SyncReleasesWithTags synchronizes release table with repository tags func SyncReleasesWithTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { log.Debug("SyncReleasesWithTags: in Repo[%d:%s/%s]", repo.ID, repo.OwnerName, repo.Name) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 3bf8aa3845009..26734f2dd6228 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2748,6 +2748,7 @@ dashboard.delete_missing_repos = Delete all repositories missing their Git files dashboard.delete_missing_repos.started = Delete all repositories missing their Git files task started. dashboard.delete_generated_repository_avatars = Delete generated repository avatars dashboard.sync_repo_branches = Sync missed branches from git data to databases +dashboard.sync_repo_tags = Sync tags from git data to database dashboard.update_mirrors = Update Mirrors dashboard.repo_health_check = Health check all repositories dashboard.check_repo_stats = Check all repository statistics @@ -2802,6 +2803,7 @@ dashboard.stop_endless_tasks = Stop endless tasks dashboard.cancel_abandoned_jobs = Cancel abandoned jobs dashboard.start_schedule_tasks = Start schedule tasks dashboard.sync_branch.started = Branches Sync started +dashboard.sync_tag.started = Tags Sync started dashboard.rebuild_issue_indexer = Rebuild issue indexer users.user_manage_panel = User Account Management diff --git a/routers/init.go b/routers/init.go index ee98aedb1655a..e0a7150ba3182 100644 --- a/routers/init.go +++ b/routers/init.go @@ -45,6 +45,7 @@ import ( repo_migrations "code.gitea.io/gitea/services/migrations" mirror_service "code.gitea.io/gitea/services/mirror" pull_service "code.gitea.io/gitea/services/pull" + release_service "code.gitea.io/gitea/services/release" repo_service "code.gitea.io/gitea/services/repository" "code.gitea.io/gitea/services/repository/archiver" "code.gitea.io/gitea/services/task" @@ -138,6 +139,8 @@ func InitWebInstalled(ctx context.Context) { mustInit(system.Init) mustInitCtx(ctx, oauth2.Init) + mustInit(release_service.Init) + mustInitCtx(ctx, models.Init) mustInitCtx(ctx, authmodel.Init) mustInitCtx(ctx, repo_service.Init) diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 5559b6af88f2c..d31cb1cd2551c 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/cron" "code.gitea.io/gitea/services/forms" + release_service "code.gitea.io/gitea/services/release" repo_service "code.gitea.io/gitea/services/repository" ) @@ -157,6 +158,13 @@ func DashboardPost(ctx *context.Context) { } }() ctx.Flash.Success(ctx.Tr("admin.dashboard.sync_branch.started")) + case "sync_repo_tags": + go func() { + if err := release_service.AddAllRepoTagsToSyncQueue(graceful.GetManager().ShutdownContext()); err != nil { + log.Error("AddAllRepoTagsToSyncQueue: %v: %v", ctx.Doer.ID, err) + } + }() + ctx.Flash.Success(ctx.Tr("admin.dashboard.sync_tag.started")) default: task := cron.GetTask(form.Op) if task != nil { diff --git a/services/release/release.go b/services/release/release.go index ddfb11fa476d4..f17682ae0f8f6 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -16,6 +16,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/storage" @@ -370,3 +371,8 @@ func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *re return nil } + +// Init start release service +func Init() error { + return initTagSyncQueue(graceful.GetManager().ShutdownContext()) +} diff --git a/services/release/tag.go b/services/release/tag.go new file mode 100644 index 0000000000000..dae2b70f76b4e --- /dev/null +++ b/services/release/tag.go @@ -0,0 +1,61 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package release + +import ( + "context" + "errors" + "fmt" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/queue" + repo_module "code.gitea.io/gitea/modules/repository" + + "xorm.io/builder" +) + +type TagSyncOptions struct { + RepoID int64 +} + +// tagSyncQueue represents a queue to handle tag sync jobs. +var tagSyncQueue *queue.WorkerPoolQueue[*TagSyncOptions] + +func handlerTagSync(items ...*TagSyncOptions) []*TagSyncOptions { + for _, opts := range items { + err := repo_module.SyncRepoTags(graceful.GetManager().ShutdownContext(), opts.RepoID) + if err != nil { + log.Error("syncRepoTags [%d] failed: %v", opts.RepoID, err) + } + } + return nil +} + +func addRepoToTagSyncQueue(repoID int64) error { + return tagSyncQueue.Push(&TagSyncOptions{ + RepoID: repoID, + }) +} + +func initTagSyncQueue(ctx context.Context) error { + tagSyncQueue = queue.CreateUniqueQueue(ctx, "tag_sync", handlerTagSync) + if tagSyncQueue == nil { + return errors.New("unable to create tag_sync queue") + } + go graceful.GetManager().RunWithCancel(tagSyncQueue) + + return nil +} + +func AddAllRepoTagsToSyncQueue(ctx context.Context) error { + if err := db.Iterate(ctx, builder.Eq{"is_empty": false}, func(ctx context.Context, repo *repo_model.Repository) error { + return addRepoToTagSyncQueue(repo.ID) + }); err != nil { + return fmt.Errorf("run sync all tags failed: %v", err) + } + return nil +} diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 65d9c370f3dd6..f43b4c5385c54 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -63,6 +63,10 @@ {{ctx.Locale.Tr "admin.dashboard.sync_repo_branches"}} + + {{ctx.Locale.Tr "admin.dashboard.sync_repo_tags"}} + +