diff --git a/Makefile b/Makefile index 830a30a924..d7da16d9d4 100644 --- a/Makefile +++ b/Makefile @@ -534,7 +534,7 @@ lint-templates: .venv node_modules .PHONY: lint-yaml lint-yaml: .venv - @poetry run yamllint . + @poetry run yamllint -s . .PHONY: security-check security-check: diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 4046c7d369..b9b9324e07 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -10,6 +10,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/translation" webhook_module "code.gitea.io/gitea/modules/webhook" "xorm.io/builder" @@ -112,14 +113,14 @@ type StatusInfo struct { } // GetStatusInfoList returns a slice of StatusInfo -func GetStatusInfoList(ctx context.Context) []StatusInfo { +func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInfo { // same as those in aggregateJobStatus allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning} statusInfoList := make([]StatusInfo, 0, 4) for _, s := range allStatus { statusInfoList = append(statusInfoList, StatusInfo{ Status: int(s), - DisplayedStatus: s.String(), + DisplayedStatus: s.LocaleString(lang), }) } return statusInfoList diff --git a/models/admin/task.go b/models/admin/task.go index c8bc95f981..5c2f7af49c 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -44,7 +44,7 @@ func init() { // TranslatableMessage represents JSON struct that can be translated with a Locale type TranslatableMessage struct { Format string - Args []any `json:"omitempty"` + Args []any `json:",omitempty"` } // LoadRepo loads repository of the task diff --git a/models/packages/package.go b/models/packages/package.go index fd408f8bef..874c7c2847 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -242,6 +242,11 @@ func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error { return err } +func UnlinkRepository(ctx context.Context, packageID int64) error { + _, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: 0}) + return err +} + // UnlinkRepositoryFromAllPackages unlinks every package from the repository func UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error { _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{}) diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go index cb47074e98..4316b4a8e1 100644 --- a/routers/api/actions/runner/runner.go +++ b/routers/api/actions/runner/runner.go @@ -158,7 +158,7 @@ func (s *Service) FetchTask( // if the task version in request is not equal to the version in db, // it means there may still be some tasks not be assigned. // try to pick a task for the runner that send the request. - if t, ok, err := pickTask(ctx, runner); err != nil { + if t, ok, err := actions_service.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 { diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go deleted file mode 100644 index 0fd7ca5c44..0000000000 --- a/routers/api/actions/runner/utils.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package runner - -import ( - "context" - "fmt" - - actions_model "code.gitea.io/gitea/models/actions" - secret_model "code.gitea.io/gitea/models/secret" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/services/actions" - - runnerv1 "code.gitea.io/actions-proto-go/runner/v1" - "google.golang.org/protobuf/types/known/structpb" -) - -func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv1.Task, bool, error) { - t, ok, err := actions_model.CreateTaskForRunner(ctx, runner) - if err != nil { - return nil, false, fmt.Errorf("CreateTaskForRunner: %w", err) - } - if !ok { - return nil, false, nil - } - - secrets, err := secret_model.GetSecretsOfTask(ctx, t) - if err != nil { - return nil, false, fmt.Errorf("GetSecretsOfTask: %w", err) - } - - vars, err := actions_model.GetVariablesOfRun(ctx, t.Job.Run) - if err != nil { - return nil, false, fmt.Errorf("GetVariablesOfRun: %w", err) - } - - actions.CreateCommitStatus(ctx, t.Job) - - task := &runnerv1.Task{ - Id: t.ID, - WorkflowPayload: t.Job.WorkflowPayload, - Context: generateTaskContext(t), - Secrets: secrets, - Vars: vars, - } - - if needs, err := findTaskNeeds(ctx, t); err != nil { - log.Error("Cannot find needs for task %v: %v", t.ID, err) - // Go on with empty needs. - // If return error, the task will be wild, which means the runner will never get it when it has been assigned to the runner. - // In contrast, missing needs is less serious. - // And the task will fail and the runner will report the error in the logs. - } else { - task.Needs = needs - } - - return task, true, nil -} - -func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct { - giteaRuntimeToken, err := actions.CreateAuthorizationToken(t.ID, t.Job.RunID, t.JobID) - if err != nil { - log.Error("actions.CreateAuthorizationToken failed: %v", err) - } - - gitCtx := actions.GenerateGiteaContext(t.Job.Run, t.Job) - gitCtx["token"] = t.Token - gitCtx["gitea_runtime_token"] = giteaRuntimeToken - - taskContext, err := structpb.NewStruct(gitCtx) - if err != nil { - log.Error("structpb.NewStruct failed: %v", err) - } - - return taskContext -} - -func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[string]*runnerv1.TaskNeed, error) { - if err := task.LoadAttributes(ctx); err != nil { - return nil, fmt.Errorf("task LoadAttributes: %w", err) - } - taskNeeds, err := actions.FindTaskNeeds(ctx, task.Job) - if err != nil { - return nil, err - } - ret := make(map[string]*runnerv1.TaskNeed, len(taskNeeds)) - for jobID, taskNeed := range taskNeeds { - ret[jobID] = &runnerv1.TaskNeed{ - Outputs: taskNeed.Outputs, - Result: runnerv1.Result(taskNeed.Result), - } - } - return ret, nil -} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 684686b1e2..3791a6fbba 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1485,13 +1485,19 @@ func Routes() *web.Route { // NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs m.Group("/packages/{username}", func() { - m.Group("/{type}/{name}/{version}", func() { - m.Get("", reqToken(), packages.GetPackage) - m.Delete("", reqToken(), reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage) - m.Get("/files", reqToken(), packages.ListPackageFiles) + m.Group("/{type}/{name}", func() { + m.Group("/{version}", func() { + m.Get("", packages.GetPackage) + m.Delete("", reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage) + m.Get("/files", packages.ListPackageFiles) + }) + + m.Post("/-/link/{repo_name}", reqPackageAccess(perm.AccessModeWrite), packages.LinkPackage) + m.Post("/-/unlink", reqPackageAccess(perm.AccessModeWrite), packages.UnlinkPackage) }) - m.Get("/", reqToken(), packages.ListPackages) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly()) + + m.Get("/", packages.ListPackages) + }, reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly()) // Organizations m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs) diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index b38aa13167..a98b5dbc69 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -4,11 +4,14 @@ package packages import ( + "errors" "net/http" "code.gitea.io/gitea/models/packages" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/optional" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" @@ -213,3 +216,122 @@ func ListPackageFiles(ctx *context.APIContext) { ctx.JSON(http.StatusOK, apiPackageFiles) } + +// LinkPackage sets a repository link for a package +func LinkPackage(ctx *context.APIContext) { + // swagger:operation POST /packages/{owner}/{type}/{name}/-/link/{repo_name} package linkPackage + // --- + // summary: Link a package to a repository + // parameters: + // - name: owner + // in: path + // description: owner of the package + // type: string + // required: true + // - name: type + // in: path + // description: type of the package + // type: string + // required: true + // - name: name + // in: path + // description: name of the package + // type: string + // required: true + // - name: repo_name + // in: path + // description: name of the repository to link. + // type: string + // required: true + // responses: + // "201": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/notFound" + + pkg, err := packages.GetPackageByName(ctx, ctx.ContextUser.ID, packages.Type(ctx.PathParamRaw("type")), ctx.PathParamRaw("name")) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "GetPackageByName", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetPackageByName", err) + } + return + } + + repo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ctx.PathParamRaw("repo_name")) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "GetRepositoryByName", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetRepositoryByName", err) + } + return + } + + err = packages_service.LinkToRepository(ctx, pkg, repo, ctx.Doer) + if err != nil { + switch { + case errors.Is(err, util.ErrInvalidArgument): + ctx.Error(http.StatusBadRequest, "LinkToRepository", err) + case errors.Is(err, util.ErrPermissionDenied): + ctx.Error(http.StatusForbidden, "LinkToRepository", err) + default: + ctx.Error(http.StatusInternalServerError, "LinkToRepository", err) + } + return + } + ctx.Status(http.StatusCreated) +} + +// UnlinkPackage sets a repository link for a package +func UnlinkPackage(ctx *context.APIContext) { + // swagger:operation POST /packages/{owner}/{type}/{name}/-/unlink package unlinkPackage + // --- + // summary: Unlink a package from a repository + // parameters: + // - name: owner + // in: path + // description: owner of the package + // type: string + // required: true + // - name: type + // in: path + // description: type of the package + // type: string + // required: true + // - name: name + // in: path + // description: name of the package + // type: string + // required: true + // responses: + // "201": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/notFound" + + pkg, err := packages.GetPackageByName(ctx, ctx.ContextUser.ID, packages.Type(ctx.PathParamRaw("type")), ctx.PathParamRaw("name")) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "GetPackageByName", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetPackageByName", err) + } + return + } + + err = packages_service.UnlinkFromRepository(ctx, pkg, ctx.Doer) + if err != nil { + switch { + case errors.Is(err, util.ErrPermissionDenied): + ctx.Error(http.StatusForbidden, "UnlinkFromRepository", err) + case errors.Is(err, util.ErrInvalidArgument): + ctx.Error(http.StatusBadRequest, "UnlinkFromRepository", err) + default: + ctx.Error(http.StatusInternalServerError, "UnlinkFromRepository", err) + } + return + } + ctx.Status(http.StatusNoContent) +} diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index e5134c1f62..e0ef709ea6 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -240,7 +240,7 @@ func List(ctx *context.Context) { } ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx.Doer, actors) - ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx) + ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx, ctx.Locale) pager := context.NewPagination(int(total), opts.PageSize, opts.Page, 5) pager.SetDefaultParams(ctx) diff --git a/services/actions/task.go b/services/actions/task.go new file mode 100644 index 0000000000..bc54ade347 --- /dev/null +++ b/services/actions/task.go @@ -0,0 +1,107 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "context" + "fmt" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + secret_model "code.gitea.io/gitea/models/secret" + + runnerv1 "code.gitea.io/actions-proto-go/runner/v1" + "google.golang.org/protobuf/types/known/structpb" +) + +func PickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv1.Task, bool, error) { + var ( + task *runnerv1.Task + job *actions_model.ActionRunJob + ) + + if err := db.WithTx(ctx, func(ctx context.Context) error { + t, ok, err := actions_model.CreateTaskForRunner(ctx, runner) + if err != nil { + return fmt.Errorf("CreateTaskForRunner: %w", err) + } + if !ok { + return nil + } + + if err := t.LoadAttributes(ctx); err != nil { + return fmt.Errorf("task LoadAttributes: %w", err) + } + job = t.Job + + secrets, err := secret_model.GetSecretsOfTask(ctx, t) + if err != nil { + return fmt.Errorf("GetSecretsOfTask: %w", err) + } + + vars, err := actions_model.GetVariablesOfRun(ctx, t.Job.Run) + if err != nil { + return fmt.Errorf("GetVariablesOfRun: %w", err) + } + + needs, err := findTaskNeeds(ctx, job) + if err != nil { + return fmt.Errorf("findTaskNeeds: %w", err) + } + + taskContext, err := generateTaskContext(t) + if err != nil { + return fmt.Errorf("generateTaskContext: %w", err) + } + + task = &runnerv1.Task{ + Id: t.ID, + WorkflowPayload: t.Job.WorkflowPayload, + Context: taskContext, + Secrets: secrets, + Vars: vars, + Needs: needs, + } + + return nil + }); err != nil { + return nil, false, err + } + + if task == nil { + return nil, false, nil + } + + CreateCommitStatus(ctx, job) + + return task, true, nil +} + +func generateTaskContext(t *actions_model.ActionTask) (*structpb.Struct, error) { + giteaRuntimeToken, err := CreateAuthorizationToken(t.ID, t.Job.RunID, t.JobID) + if err != nil { + return nil, err + } + + gitCtx := GenerateGiteaContext(t.Job.Run, t.Job) + gitCtx["token"] = t.Token + gitCtx["gitea_runtime_token"] = giteaRuntimeToken + + return structpb.NewStruct(gitCtx) +} + +func findTaskNeeds(ctx context.Context, taskJob *actions_model.ActionRunJob) (map[string]*runnerv1.TaskNeed, error) { + taskNeeds, err := FindTaskNeeds(ctx, taskJob) + if err != nil { + return nil, err + } + ret := make(map[string]*runnerv1.TaskNeed, len(taskNeeds)) + for jobID, taskNeed := range taskNeeds { + ret[jobID] = &runnerv1.TaskNeed{ + Outputs: taskNeed.Outputs, + Result: runnerv1.Result(taskNeed.Result), + } + } + return ret, nil +} diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 2a213ae515..23eb0dd291 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -54,7 +54,7 @@ func registerRepoHealthCheck() { RunAtStart: false, Schedule: "@midnight", }, - Timeout: 60 * time.Second, + Timeout: time.Duration(setting.Git.Timeout.Default) * time.Second, Args: []string{}, }, func(ctx context.Context, _ *user_model.User, config Config) error { rhcConfig := config.(*RepoHealthCheckConfig) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index b180cf498f..085995df4f 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -135,7 +135,9 @@ func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult { case strings.HasPrefix(lines[i], " - "): // Delete reference isTag := !strings.HasPrefix(refName, remoteName+"/") var refFullName git.RefName - if isTag { + if strings.HasPrefix(refName, "refs/") { + refFullName = git.RefName(refName) + } else if isTag { refFullName = git.RefNameFromTag(refName) } else { refFullName = git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")) @@ -158,8 +160,15 @@ func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult { log.Error("Expect two SHAs but not what found: %q", lines[i]) continue } + var refFullName git.RefName + if strings.HasPrefix(refName, "refs/") { + refFullName = git.RefName(refName) + } else { + refFullName = git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")) + } + results = append(results, &mirrorSyncResult{ - refName: git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")), + refName: refFullName, oldCommitID: shas[0], newCommitID: shas[1], }) diff --git a/services/mirror/mirror_test.go b/services/mirror/mirror_test.go index e26204e2ec..76632b6872 100644 --- a/services/mirror/mirror_test.go +++ b/services/mirror/mirror_test.go @@ -17,11 +17,13 @@ func Test_parseRemoteUpdateOutput(t *testing.T) { - [deleted] (none) -> tag1 + f895a1e...957a993 test2 -> origin/test2 (forced update) 957a993..a87ba5f test3 -> origin/test3 - * [new ref] refs/pull/27/merge -> refs/pull/27/merge - * [new ref] refs/pull/516/head -> refs/pull/516/head - ` + * [new ref] refs/pull/26595/head -> refs/pull/26595/head + * [new ref] refs/pull/26595/merge -> refs/pull/26595/merge + e0639e38fb..6db2410489 refs/pull/25873/head -> refs/pull/25873/head + + 1c97ebc746...976d27d52f refs/pull/25873/merge -> refs/pull/25873/merge (forced update) +` results := parseRemoteUpdateOutput(output, "origin") - assert.Len(t, results, 8) + assert.Len(t, results, 10) assert.EqualValues(t, "refs/tags/v0.1.8", results[0].refName.String()) assert.EqualValues(t, gitShortEmptySha, results[0].oldCommitID) assert.EqualValues(t, "", results[0].newCommitID) @@ -46,11 +48,19 @@ func Test_parseRemoteUpdateOutput(t *testing.T) { assert.EqualValues(t, "957a993", results[5].oldCommitID) assert.EqualValues(t, "a87ba5f", results[5].newCommitID) - assert.EqualValues(t, "refs/pull/27/merge", results[6].refName.String()) + assert.EqualValues(t, "refs/pull/26595/head", results[6].refName.String()) assert.EqualValues(t, gitShortEmptySha, results[6].oldCommitID) assert.EqualValues(t, "", results[6].newCommitID) - assert.EqualValues(t, "refs/pull/516/head", results[7].refName.String()) + assert.EqualValues(t, "refs/pull/26595/merge", results[7].refName.String()) assert.EqualValues(t, gitShortEmptySha, results[7].oldCommitID) assert.EqualValues(t, "", results[7].newCommitID) + + assert.EqualValues(t, "refs/pull/25873/head", results[8].refName.String()) + assert.EqualValues(t, "e0639e38fb", results[8].oldCommitID) + assert.EqualValues(t, "6db2410489", results[8].newCommitID) + + assert.EqualValues(t, "refs/pull/25873/merge", results[9].refName.String()) + assert.EqualValues(t, "1c97ebc746", results[9].oldCommitID) + assert.EqualValues(t, "976d27d52f", results[9].newCommitID) } diff --git a/services/packages/package_update.go b/services/packages/package_update.go new file mode 100644 index 0000000000..8d851fac53 --- /dev/null +++ b/services/packages/package_update.go @@ -0,0 +1,78 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package packages + +import ( + "context" + "fmt" + + org_model "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/util" +) + +func LinkToRepository(ctx context.Context, pkg *packages_model.Package, repo *repo_model.Repository, doer *user_model.User) error { + if pkg.OwnerID != repo.OwnerID { + return util.ErrPermissionDenied + } + if pkg.RepoID > 0 { + return util.ErrInvalidArgument + } + + perms, err := access_model.GetUserRepoPermission(ctx, repo, doer) + if err != nil { + return fmt.Errorf("error getting permissions for user %d on repository %d: %w", doer.ID, repo.ID, err) + } + if !perms.CanWrite(unit.TypePackages) { + return util.ErrPermissionDenied + } + + if err := packages_model.SetRepositoryLink(ctx, pkg.ID, repo.ID); err != nil { + return fmt.Errorf("error while linking package '%v' to repo '%v' : %w", pkg.Name, repo.FullName(), err) + } + return nil +} + +func UnlinkFromRepository(ctx context.Context, pkg *packages_model.Package, doer *user_model.User) error { + if pkg.RepoID == 0 { + return util.ErrInvalidArgument + } + + repo, err := repo_model.GetRepositoryByID(ctx, pkg.RepoID) + if err != nil { + return fmt.Errorf("error getting repository %d: %w", pkg.RepoID, err) + } + + perms, err := access_model.GetUserRepoPermission(ctx, repo, doer) + if err != nil { + return fmt.Errorf("error getting permissions for user %d on repository %d: %w", doer.ID, repo.ID, err) + } + if !perms.CanWrite(unit.TypePackages) { + return util.ErrPermissionDenied + } + + user, err := user_model.GetUserByID(ctx, pkg.OwnerID) + if err != nil { + return err + } + if !doer.IsAdmin { + if !user.IsOrganization() { + if doer.ID != pkg.OwnerID { + return fmt.Errorf("no permission to unlink package '%v' from its repository, or packages are disabled", pkg.Name) + } + } else { + isOrgAdmin, err := org_model.OrgFromUser(user).IsOrgAdmin(ctx, doer.ID) + if err != nil { + return err + } else if !isOrgAdmin { + return fmt.Errorf("no permission to unlink package '%v' from its repository, or packages are disabled", pkg.Name) + } + } + } + return packages_model.UnlinkRepository(ctx, pkg.ID) +} diff --git a/services/repository/delete.go b/services/repository/delete.go index 6e84194750..09213e5c65 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -16,6 +16,7 @@ import ( git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" access_model "code.gitea.io/gitea/models/perm/access" project_model "code.gitea.io/gitea/models/project" repo_model "code.gitea.io/gitea/models/repo" @@ -28,6 +29,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + federation_service "code.gitea.io/gitea/services/federation" "xorm.io/builder" ) @@ -289,6 +291,15 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID return err } + if err := federation_service.DeleteFollowingRepos(ctx, repo.ID); err != nil { + return err + } + + // unlink packages linked to this repository + if err = packages_model.UnlinkRepositoryFromAllPackages(ctx, repoID); err != nil { + return err + } + if err = committer.Commit(); err != nil { return err } diff --git a/services/repository/repository.go b/services/repository/repository.go index 116e24151b..35bcdfd528 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/models/unit" @@ -22,7 +21,6 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" - federation_service "code.gitea.io/gitea/services/federation" notify_service "code.gitea.io/gitea/services/notify" pull_service "code.gitea.io/gitea/services/pull" ) @@ -64,15 +62,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod notify_service.DeleteRepository(ctx, doer, repo) } - if err := DeleteRepositoryDirectly(ctx, doer, repo.ID); err != nil { - return err - } - - if err := federation_service.DeleteFollowingRepos(ctx, repo.ID); err != nil { - return err - } - - return packages_model.UnlinkRepositoryFromAllPackages(ctx, repo.ID) + return DeleteRepositoryDirectly(ctx, doer, repo.ID) } // PushCreateRepo creates a repository when a new repository is pushed to an appropriate namespace diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index ba17222f9b..0825dbf7bc 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -194,11 +194,13 @@ {{else}} {{if .ShowRegistrationButton}} - {{svg "octicon-person"}} {{ctx.Locale.Tr "register"}} + {{svg "octicon-person"}} + {{ctx.Locale.Tr "register"}} {{end}} - {{svg "octicon-sign-in"}} {{ctx.Locale.Tr "sign_in"}} + {{svg "octicon-sign-in"}} + {{ctx.Locale.Tr "sign_in"}} {{end}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 037ee48b8c..7ff9825bbb 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4159,6 +4159,93 @@ } } }, + "/packages/{owner}/{type}/{name}/-/link/{repo_name}": { + "post": { + "tags": [ + "package" + ], + "summary": "Link a package to a repository", + "operationId": "linkPackage", + "parameters": [ + { + "type": "string", + "description": "owner of the package", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "type of the package", + "name": "type", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the package", + "name": "name", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repository to link.", + "name": "repo_name", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "$ref": "#/responses/empty" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, + "/packages/{owner}/{type}/{name}/-/unlink": { + "post": { + "tags": [ + "package" + ], + "summary": "Unlink a package from a repository", + "operationId": "unlinkPackage", + "parameters": [ + { + "type": "string", + "description": "owner of the package", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "type of the package", + "name": "type", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the package", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "$ref": "#/responses/empty" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/packages/{owner}/{type}/{name}/{version}": { "get": { "produces": [ diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index 9cedc498fe..b8783dead0 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -78,7 +78,16 @@
{{ctx.Locale.Tr "settings.ssh_token_help"}}
-{{printf "echo -n '%s' | ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey" $.TokenToSign}}
echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey
cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey"
set /p={{$.TokenToSign}}| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey