mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-12 00:22:59 +02:00
updated DeleteOrgRepos to delete in the background
This commit is contained in:
parent
ed4b335f9f
commit
5b819b42aa
@ -440,25 +440,3 @@ type UpdateRepoAvatarOption struct {
|
||||
// image must be base64 encoded
|
||||
Image string `json:"image" binding:"Required"`
|
||||
}
|
||||
|
||||
// DeleteOrgReposResponse represents the response for deleting organization repositories
|
||||
// swagger:model
|
||||
type DeleteOrgReposResponse struct {
|
||||
// Number of repositories successfully deleted
|
||||
SuccessCount int `json:"success_count"`
|
||||
// Number of repositories that failed to delete
|
||||
FailureCount int `json:"failure_count"`
|
||||
// List of repository names that were deleted
|
||||
Deleted []string `json:"deleted"`
|
||||
// Details about repositories that failed to delete
|
||||
Failed []DeleteRepoFailure `json:"failed"`
|
||||
}
|
||||
|
||||
// DeleteRepoFailure represents a repository that failed to delete
|
||||
// swagger:model
|
||||
type DeleteRepoFailure struct {
|
||||
// Repository name
|
||||
RepoName string `json:"repo_name"`
|
||||
// Message to be displayed
|
||||
Message string `json:"reason"`
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
@ -510,8 +511,8 @@ func DeleteOrgRepos(ctx *context.APIContext) {
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/DeleteOrgReposList"
|
||||
// "202":
|
||||
// description: Deletion started
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
@ -522,22 +523,29 @@ func DeleteOrgRepos(ctx *context.APIContext) {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
response := &api.DeleteOrgReposResponse{
|
||||
Deleted: []string{},
|
||||
Failed: []api.DeleteRepoFailure{},
|
||||
}
|
||||
for _, repo := range repos {
|
||||
if err := repo_service.DeleteRepository(ctx, ctx.Doer, repo, true); err != nil {
|
||||
log.Error("Error deleting repo %s: %v", repo.Name, err)
|
||||
response.Failed = append(response.Failed, api.DeleteRepoFailure{
|
||||
RepoName: repo.Name,
|
||||
Message: "Failed to delete repository",
|
||||
})
|
||||
} else {
|
||||
response.Deleted = append(response.Deleted, repo.Name)
|
||||
|
||||
doer := ctx.Doer
|
||||
|
||||
// Start deletion in background with detached context
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Error("Panic during org repo deletion: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// Use HammerContext so deletion continues even if client disconnects
|
||||
bgCtx := graceful.GetManager().HammerContext()
|
||||
|
||||
for _, repo := range repos {
|
||||
if err := repo_service.DeleteRepository(bgCtx, doer, repo, true); err != nil {
|
||||
log.Error("Failed to delete repository %s (ID: %d) in org %s: %v", repo.Name, repo.ID, org.Name, err)
|
||||
} else {
|
||||
log.Info("Successfully deleted repository %s (ID: %d) in org %s", repo.Name, repo.ID, org.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
response.SuccessCount = len(response.Deleted)
|
||||
response.FailureCount = len(response.Failed)
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
log.Info("Completed deletion of %d repositories in org %s", len(repos), org.Name)
|
||||
}()
|
||||
|
||||
ctx.Status(http.StatusAccepted)
|
||||
}
|
||||
|
||||
@ -41,11 +41,3 @@ type swaggerResponseOrganizationPermissions struct {
|
||||
// in:body
|
||||
Body api.OrganizationPermissions `json:"body"`
|
||||
}
|
||||
|
||||
// DeleteOrgReposList
|
||||
// swagger:response DeleteOrgReposList
|
||||
type swaggerDeleteOrgReposList struct {
|
||||
// List of successfully deleted repositories and failures
|
||||
//in:body
|
||||
Body api.DeleteOrgReposResponse `json:"body"`
|
||||
}
|
||||
|
||||
62
templates/swagger/v1_json.tmpl
generated
62
templates/swagger/v1_json.tmpl
generated
@ -3658,8 +3658,8 @@
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/DeleteOrgReposList"
|
||||
"202": {
|
||||
"description": "Deletion started"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
@ -24210,58 +24210,6 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"DeleteOrgReposResponse": {
|
||||
"description": "DeleteOrgReposResponse represents the response for deleting organization repositories",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"deleted": {
|
||||
"description": "List of repository names that were deleted",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "Deleted"
|
||||
},
|
||||
"failed": {
|
||||
"description": "Details about repositories that failed to delete",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/DeleteRepoFailure"
|
||||
},
|
||||
"x-go-name": "Failed"
|
||||
},
|
||||
"failure_count": {
|
||||
"description": "Number of repositories that failed to delete",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "FailureCount"
|
||||
},
|
||||
"success_count": {
|
||||
"description": "Number of repositories successfully deleted",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "SuccessCount"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"DeleteRepoFailure": {
|
||||
"description": "DeleteRepoFailure represents a repository that failed to delete",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"description": "Message to be displayed",
|
||||
"type": "string",
|
||||
"x-go-name": "Message"
|
||||
},
|
||||
"repo_name": {
|
||||
"description": "Repository name",
|
||||
"type": "string",
|
||||
"x-go-name": "RepoName"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"DeployKey": {
|
||||
"description": "DeployKey a deploy key",
|
||||
"type": "object",
|
||||
@ -29810,12 +29758,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"DeleteOrgReposList": {
|
||||
"description": "DeleteOrgReposList",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/DeleteOrgReposResponse"
|
||||
}
|
||||
},
|
||||
"DeployKey": {
|
||||
"description": "DeployKey",
|
||||
"schema": {
|
||||
|
||||
@ -275,17 +275,9 @@ func TestAPIDeleteOrgRepos(t *testing.T) {
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
|
||||
// Delete all repos
|
||||
// Delete all repos - should return 202 Accepted
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/orgs/%s/repos", orgName)).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result api.DeleteOrgReposResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, 60, result.SuccessCount)
|
||||
assert.Equal(t, 0, result.FailureCount)
|
||||
assert.Len(t, result.Deleted, 60)
|
||||
assert.Empty(t, result.Failed)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
})
|
||||
|
||||
t.Run("Verify response structure", func(t *testing.T) {
|
||||
@ -308,20 +300,9 @@ func TestAPIDeleteOrgRepos(t *testing.T) {
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
|
||||
// Delete all repos
|
||||
// Delete all repos - should return 202 Accepted
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/orgs/%s/repos", orgName)).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result api.DeleteOrgReposResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
// Verify response structure
|
||||
assert.Equal(t, 3, result.SuccessCount)
|
||||
assert.Equal(t, 0, result.FailureCount)
|
||||
assert.Len(t, result.Deleted, 3)
|
||||
assert.Empty(t, result.Failed)
|
||||
assert.NotNil(t, result.Deleted)
|
||||
assert.NotNil(t, result.Failed)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
})
|
||||
|
||||
t.Run("Fail without permissions", func(t *testing.T) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user