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:
parent
acf9dc0148
commit
e940dd27b1
@ -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"`
|
||||
}
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"`
|
||||
}
|
||||
|
||||
88
templates/swagger/v1_json.tmpl
generated
88
templates/swagger/v1_json.tmpl
generated
@ -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": {
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user