mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-08 16:45:30 +00:00
Add DeletePipeline API (#3506)
This is just a first step, the final goal is to have an API endpoint to prune Repo Pipelines older than the given date. @woodpecker-ci/maintainers Can I get some feedback if this is the right direction? --------- Co-authored-by: 6543 <m.huber@kithara.com>
This commit is contained in:
parent
9972c24924
commit
d0057736f1
5 changed files with 141 additions and 4 deletions
|
@ -2339,6 +2339,44 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"produces": [
|
||||
"text/plain"
|
||||
],
|
||||
"tags": [
|
||||
"Pipelines"
|
||||
],
|
||||
"summary": "Delete pipeline",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cpersonal access token\u003e",
|
||||
"description": "Insert your personal access token",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "the repository id",
|
||||
"name": "repo_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "the number of the pipeline",
|
||||
"name": "number",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{repo_id}/pipelines/{number}/approve": {
|
||||
|
|
|
@ -64,3 +64,14 @@ func refreshUserToken(c *gin.Context, user *model.User) {
|
|||
}
|
||||
forge.Refresh(c, _forge, _store, user)
|
||||
}
|
||||
|
||||
// pipelineDeleteAllowed checks if the given pipeline can be deleted based on its status.
|
||||
// It returns a bool indicating if delete is allowed, and the pipeline's status.
|
||||
func pipelineDeleteAllowed(pl *model.Pipeline) bool {
|
||||
switch pl.Status {
|
||||
case model.StatusRunning, model.StatusPending, model.StatusBlocked:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -144,6 +144,46 @@ func GetPipelines(c *gin.Context) {
|
|||
c.JSON(http.StatusOK, pipelines)
|
||||
}
|
||||
|
||||
// DeletePipeline
|
||||
//
|
||||
// @Summary Delete pipeline
|
||||
// @Router /repos/{repo_id}/pipelines/{number} [delete]
|
||||
// @Produce plain
|
||||
// @Success 204
|
||||
// @Tags Pipelines
|
||||
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
|
||||
// @Param repo_id path int true "the repository id"
|
||||
// @Param number path int true "the number of the pipeline"
|
||||
func DeletePipeline(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
|
||||
repo := session.Repo(c)
|
||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
pl, err := _store.GetPipelineNumber(repo, num)
|
||||
if err != nil {
|
||||
handleDBError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if ok := pipelineDeleteAllowed(pl); !ok {
|
||||
c.String(http.StatusUnprocessableEntity, "Cannot delete pipeline with status %s", pl.Status)
|
||||
return
|
||||
}
|
||||
|
||||
err = store.FromContext(c).DeletePipeline(pl)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Error deleting pipeline. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// GetPipeline
|
||||
//
|
||||
// @Summary Pipeline information by number
|
||||
|
@ -574,9 +614,8 @@ func DeletePipelineLogs(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
switch pl.Status {
|
||||
case model.StatusRunning, model.StatusPending:
|
||||
c.String(http.StatusUnprocessableEntity, "Cannot delete logs for a pending or running pipeline")
|
||||
if ok := pipelineDeleteAllowed(pl); !ok {
|
||||
c.String(http.StatusUnprocessableEntity, "Cannot delete logs for pipeline with status %s", pl.Status)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -586,7 +625,7 @@ func DeletePipelineLogs(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "There was a problem deleting your logs. %s", err)
|
||||
c.String(http.StatusInternalServerError, "Error deleting pipeline logs. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -79,3 +79,51 @@ func TestGetPipelines(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeletePipeline(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Pipeline", func() {
|
||||
g.It("should delete pipeline", func() {
|
||||
mockStore := mocks.NewStore(t)
|
||||
mockStore.On("GetPipelineNumber", mock.Anything, mock.Anything).Return(fakePipeline, nil)
|
||||
mockStore.On("DeletePipeline", mock.Anything).Return(nil)
|
||||
|
||||
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
c.Set("store", mockStore)
|
||||
c.Params = gin.Params{{Key: "number", Value: "1"}}
|
||||
|
||||
DeletePipeline(c)
|
||||
|
||||
mockStore.AssertCalled(t, "GetPipelineNumber", mock.Anything, mock.Anything)
|
||||
mockStore.AssertCalled(t, "DeletePipeline", mock.Anything)
|
||||
assert.Equal(t, http.StatusNoContent, c.Writer.Status())
|
||||
})
|
||||
|
||||
g.It("should not delete without pipeline number", func() {
|
||||
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
|
||||
DeletePipeline(c)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, c.Writer.Status())
|
||||
})
|
||||
|
||||
g.It("should not delete pending", func() {
|
||||
fakePipeline.Status = model.StatusPending
|
||||
|
||||
mockStore := mocks.NewStore(t)
|
||||
mockStore.On("GetPipelineNumber", mock.Anything, mock.Anything).Return(fakePipeline, nil)
|
||||
|
||||
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||
c.Set("store", mockStore)
|
||||
c.Params = gin.Params{{Key: "number", Value: "1"}}
|
||||
|
||||
DeletePipeline(c)
|
||||
|
||||
mockStore.AssertCalled(t, "GetPipelineNumber", mock.Anything, mock.Anything)
|
||||
mockStore.AssertNotCalled(t, "DeletePipeline", mock.Anything)
|
||||
assert.Equal(t, http.StatusUnprocessableEntity, c.Writer.Status())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ func apiRoutes(e *gin.RouterGroup) {
|
|||
|
||||
repo.GET("/pipelines", api.GetPipelines)
|
||||
repo.POST("/pipelines", session.MustPush, api.CreatePipeline)
|
||||
repo.DELETE("/pipelines/:number", session.MustRepoAdmin(), api.DeletePipeline)
|
||||
repo.GET("/pipelines/:number", api.GetPipeline)
|
||||
repo.GET("/pipelines/:number/config", api.GetPipelineConfig)
|
||||
|
||||
|
|
Loading…
Reference in a new issue