0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-14 17:27:39 +02:00

Verified and tested the DeleteRepoOrgs

This commit is contained in:
karthikbhandary2 2026-02-26 13:59:44 +05:30
parent acf9dc0148
commit e940dd27b1
6 changed files with 211 additions and 7 deletions

View File

@ -441,14 +441,23 @@ type UpdateRepoAvatarOption struct {
Image string `json:"image" binding:"Required"`
}
// DeleteOrgReposResponse represents the response for deleting organization repositories
// swagger:model
type DeleteOrgReposResponse struct {
SuccessCount int `json:"success_count"`
FailureCount int `json:"failure_count"`
Deleted []string `json:"deleted"`
Failed []DeleteRepoFailure `json:"failed"`
// 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
type DeleteRepoFailure struct {
// Repository name
RepoName string `json:"repo_name"`
Reason string `json:"reason"`
// Reason for deletion failure
Reason string `json:"reason"`
}

View File

@ -1622,7 +1622,7 @@ func Routes() *web.Router {
m.Post("/rename", reqToken(), reqOrgOwnership(), bind(api.RenameOrgOption{}), org.Rename)
m.Combo("/repos").Get(user.ListOrgRepos).
Post(reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo).
Delete(reqToken(), reqOrgOwnership(), repo.DeleteOrgRepo)
Delete(reqToken(), reqOrgOwnership(), org.DeleteOrgRepos)
m.Group("/members", func() {
m.Get("", reqToken(), org.ListMembers)
m.Combo("/{username}").Get(reqToken(), org.IsMember).

View File

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"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/optional"
repo_module "code.gitea.io/gitea/modules/repository"
@ -22,6 +23,7 @@ import (
"code.gitea.io/gitea/services/convert"
feed_service "code.gitea.io/gitea/services/feed"
"code.gitea.io/gitea/services/org"
repo_service "code.gitea.io/gitea/services/repository"
user_service "code.gitea.io/gitea/services/user"
)
@ -509,7 +511,7 @@ func DeleteOrgRepos(ctx *context.APIContext) {
// required: true
// responses:
// "200":
// "$ref": "#/responses/DeleteOrgReposResponse"
// "$ref": "#/responses/DeleteOrgReposList"
// "403":
// "$ref": "#/responses/forbidden"
org := ctx.Org.Organization

View File

@ -41,3 +41,11 @@ 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"`
}

View File

@ -3638,6 +3638,33 @@
"$ref": "#/responses/notFound"
}
}
},
"delete": {
"produces": [
"application/json"
],
"tags": [
"organization"
],
"summary": "Delete all repositories in an organization",
"operationId": "orgDeleteRepos",
"parameters": [
{
"type": "string",
"description": "name of the organization",
"name": "org",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/DeleteOrgReposList"
},
"403": {
"$ref": "#/responses/forbidden"
}
}
}
},
"/orgs/{org}/teams": {
@ -24180,6 +24207,58 @@
},
"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": "Reason for deletion failure",
"type": "string",
"x-go-name": "Reason"
},
"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",
@ -29728,6 +29807,15 @@
}
}
},
"DeleteOrgReposList": {
"description": "DeleteOrgReposList",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/DeleteOrgReposResponse"
}
}
},
"DeployKey": {
"description": "DeployKey",
"schema": {

View File

@ -249,3 +249,100 @@ func TestAPIOrgGeneral(t *testing.T) {
MakeRequest(t, req, http.StatusForbidden)
})
}
func TestAPIDeleteOrgRepos(t *testing.T) {
defer tests.PrepareTestEnv(t)()
t.Run("Delete all repos successfully", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// Create test org with owner
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
orgName := "test_delete_org"
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &api.CreateOrgOption{
UserName: orgName,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
// Create 60 repos to test efficiency
for i := range 60 {
repoName := fmt.Sprintf("test_repo_%d", i)
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", orgName), &api.CreateRepoOption{
Name: repoName,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
}
// Delete all repos
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)
})
t.Run("Verify response structure", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
orgName := "test_response_org"
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &api.CreateOrgOption{
UserName: orgName,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
// Create a few repos
for i := range 3 {
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", orgName), &api.CreateRepoOption{
Name: fmt.Sprintf("repo_%d", i),
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
}
// Delete all repos
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)
})
t.Run("Fail without permissions", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// user2 is owner of org3
ownerSession := loginUser(t, "user2")
ownerToken := getTokenForLoggedInUser(t, ownerSession, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
// Create repo in org3
req := NewRequestWithJSON(t, "POST", "/api/v1/org/org3/repos", &api.CreateRepoOption{
Name: "test_perm_repo",
}).AddTokenAuth(ownerToken)
MakeRequest(t, req, http.StatusCreated)
// user4 is not owner of org3
nonOwnerSession := loginUser(t, "user4")
nonOwnerToken := getTokenForLoggedInUser(t, nonOwnerSession, auth_model.AccessTokenScopeWriteOrganization)
// Try to delete repos without owner permission
req = NewRequest(t, "DELETE", "/api/v1/orgs/org3/repos").AddTokenAuth(nonOwnerToken)
MakeRequest(t, req, http.StatusForbidden)
})
}