From ecbc04201d59002ee12bb7f286445039a2bfb295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Dageli=C4=87?= Date: Fri, 20 Sep 2024 14:34:13 +0200 Subject: [PATCH] feat: force build deletion (#1135) Signed-off-by: Ivan Dagelic --- docs/daytona_build_delete.md | 1 + hack/docs/daytona_build_delete.yaml | 4 ++ .../server/workspaces/mocks/build_service.go | 4 +- pkg/api/controllers/build/build.go | 47 +++++++++++++++++-- pkg/api/docs/docs.go | 22 +++++++++ pkg/api/docs/swagger.json | 22 +++++++++ pkg/api/docs/swagger.yaml | 15 ++++++ pkg/apiclient/api/openapi.yaml | 18 +++++++ pkg/apiclient/api_build.go | 30 ++++++++++++ pkg/apiclient/docs/BuildAPI.md | 23 ++++++--- pkg/apiclient/docs/BuildBuildState.md | 2 + pkg/apiclient/model_build_build_state.go | 16 ++++--- pkg/build/build.go | 15 +++--- pkg/build/runner.go | 8 +++- pkg/cmd/build/delete.go | 14 +++--- pkg/server/builds/service.go | 11 +++-- pkg/server/builds/service_test.go | 2 +- pkg/server/projectconfig/prebuild.go | 4 +- pkg/server/projectconfig/prebuild_test.go | 4 +- pkg/server/purge.go | 2 +- 20 files changed, 220 insertions(+), 44 deletions(-) diff --git a/docs/daytona_build_delete.md b/docs/daytona_build_delete.md index f28417c951..7e8710a650 100644 --- a/docs/daytona_build_delete.md +++ b/docs/daytona_build_delete.md @@ -10,6 +10,7 @@ daytona build delete [BUILD] [flags] ``` -a, --all Delete ALL builds + -f, --force Force delete build --prebuild-id string Delete ALL builds from prebuild ``` diff --git a/hack/docs/daytona_build_delete.yaml b/hack/docs/daytona_build_delete.yaml index 13b951017e..36b845e633 100644 --- a/hack/docs/daytona_build_delete.yaml +++ b/hack/docs/daytona_build_delete.yaml @@ -6,6 +6,10 @@ options: shorthand: a default_value: "false" usage: Delete ALL builds + - name: force + shorthand: f + default_value: "false" + usage: Force delete build - name: prebuild-id usage: Delete ALL builds from prebuild inherited_options: diff --git a/internal/testing/server/workspaces/mocks/build_service.go b/internal/testing/server/workspaces/mocks/build_service.go index 41b1f4338c..4e91444b0a 100644 --- a/internal/testing/server/workspaces/mocks/build_service.go +++ b/internal/testing/server/workspaces/mocks/build_service.go @@ -37,8 +37,8 @@ func (m *MockBuildService) List(filter *build.Filter) ([]*build.Build, error) { return args.Get(0).([]*build.Build), args.Error(1) } -func (m *MockBuildService) MarkForDeletion(filter *build.Filter) []error { - args := m.Called(filter) +func (m *MockBuildService) MarkForDeletion(filter *build.Filter, force bool) []error { + args := m.Called(filter, force) return args.Get(0).([]error) } diff --git a/pkg/api/controllers/build/build.go b/pkg/api/controllers/build/build.go index d6d3d66dea..36ea2f8d51 100644 --- a/pkg/api/controllers/build/build.go +++ b/pkg/api/controllers/build/build.go @@ -4,8 +4,10 @@ package build import ( + "errors" "fmt" "net/http" + "strconv" "github.com/daytonaio/daytona/pkg/api/controllers/build/dto" "github.com/daytonaio/daytona/pkg/build" @@ -139,14 +141,27 @@ func ListBuilds(ctx *gin.Context) { // @Tags build // @Summary Delete ALL builds // @Description Delete ALL builds +// @Param force query bool false "Force" // @Success 204 // @Router /build [delete] // // @id DeleteAllBuilds func DeleteAllBuilds(ctx *gin.Context) { + forceQuery := ctx.Query("force") + var force bool + var err error + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + server := server.GetInstance(nil) - errs := server.BuildService.MarkForDeletion(nil) + errs := server.BuildService.MarkForDeletion(nil, force) if len(errs) > 0 { for _, err := range errs { _ = ctx.Error(err) @@ -164,18 +179,30 @@ func DeleteAllBuilds(ctx *gin.Context) { // @Summary Delete build // @Description Delete build // @Param buildId path string true "Build ID" +// @Param force query bool false "Force" // @Success 204 // @Router /build/{buildId} [delete] // // @id DeleteBuild func DeleteBuild(ctx *gin.Context) { buildId := ctx.Param("buildId") + forceQuery := ctx.Query("force") + var force bool + var err error + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } server := server.GetInstance(nil) errs := server.BuildService.MarkForDeletion(&build.Filter{ Id: &buildId, - }) + }, force) if len(errs) > 0 { for _, err := range errs { _ = ctx.Error(err) @@ -193,17 +220,29 @@ func DeleteBuild(ctx *gin.Context) { // @Summary Delete builds // @Description Delete builds // @Param prebuildId path string true "Prebuild ID" +// @Param force query bool false "Force" // @Success 204 // @Router /build/prebuild/{prebuildId} [delete] // // @id DeleteBuildsFromPrebuild func DeleteBuildsFromPrebuild(ctx *gin.Context) { prebuildId := ctx.Param("prebuildId") + forceQuery := ctx.Query("force") + var force bool + var err error + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } server := server.GetInstance(nil) // Fail if prebuild does not exist - _, err := server.ProjectConfigService.FindPrebuild(nil, &config.PrebuildFilter{ + _, err = server.ProjectConfigService.FindPrebuild(nil, &config.PrebuildFilter{ Id: &prebuildId, }) if err != nil { @@ -213,7 +252,7 @@ func DeleteBuildsFromPrebuild(ctx *gin.Context) { errs := server.BuildService.MarkForDeletion(&build.Filter{ PrebuildIds: &[]string{prebuildId}, - }) + }, force) if len(errs) > 0 { for _, err := range errs { _ = ctx.Error(err) diff --git a/pkg/api/docs/docs.go b/pkg/api/docs/docs.go index 7ffc5835f1..9b95f53137 100644 --- a/pkg/api/docs/docs.go +++ b/pkg/api/docs/docs.go @@ -151,6 +151,14 @@ const docTemplate = `{ ], "summary": "Delete ALL builds", "operationId": "DeleteAllBuilds", + "parameters": [ + { + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" + } + ], "responses": { "204": { "description": "No Content" @@ -173,6 +181,12 @@ const docTemplate = `{ "name": "prebuildId", "in": "path", "required": true + }, + { + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { @@ -225,6 +239,12 @@ const docTemplate = `{ "name": "buildId", "in": "path", "required": true + }, + { + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { @@ -2803,6 +2823,7 @@ const docTemplate = `{ "success", "published", "pending-delete", + "pending-forced-delete", "deleting" ], "x-enum-varnames": [ @@ -2812,6 +2833,7 @@ const docTemplate = `{ "BuildStateSuccess", "BuildStatePublished", "BuildStatePendingDelete", + "BuildStatePendingForcedDelete", "BuildStateDeleting" ] }, diff --git a/pkg/api/docs/swagger.json b/pkg/api/docs/swagger.json index cce5d05241..edf8892c8b 100644 --- a/pkg/api/docs/swagger.json +++ b/pkg/api/docs/swagger.json @@ -148,6 +148,14 @@ ], "summary": "Delete ALL builds", "operationId": "DeleteAllBuilds", + "parameters": [ + { + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" + } + ], "responses": { "204": { "description": "No Content" @@ -170,6 +178,12 @@ "name": "prebuildId", "in": "path", "required": true + }, + { + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { @@ -222,6 +236,12 @@ "name": "buildId", "in": "path", "required": true + }, + { + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { @@ -2800,6 +2820,7 @@ "success", "published", "pending-delete", + "pending-forced-delete", "deleting" ], "x-enum-varnames": [ @@ -2809,6 +2830,7 @@ "BuildStateSuccess", "BuildStatePublished", "BuildStatePendingDelete", + "BuildStatePendingForcedDelete", "BuildStateDeleting" ] }, diff --git a/pkg/api/docs/swagger.yaml b/pkg/api/docs/swagger.yaml index f67b6af85e..dd57ad26e1 100644 --- a/pkg/api/docs/swagger.yaml +++ b/pkg/api/docs/swagger.yaml @@ -753,6 +753,7 @@ definitions: - success - published - pending-delete + - pending-forced-delete - deleting type: string x-enum-varnames: @@ -762,6 +763,7 @@ definitions: - BuildStateSuccess - BuildStatePublished - BuildStatePendingDelete + - BuildStatePendingForcedDelete - BuildStateDeleting provider.ProviderInfo: properties: @@ -883,6 +885,11 @@ paths: delete: description: Delete ALL builds operationId: DeleteAllBuilds + parameters: + - description: Force + in: query + name: force + type: boolean responses: "204": description: No Content @@ -934,6 +941,10 @@ paths: name: buildId required: true type: string + - description: Force + in: query + name: force + type: boolean responses: "204": description: No Content @@ -969,6 +980,10 @@ paths: name: prebuildId required: true type: string + - description: Force + in: query + name: force + type: boolean responses: "204": description: No Content diff --git a/pkg/apiclient/api/openapi.yaml b/pkg/apiclient/api/openapi.yaml index f65c3b1c0b..59033d3f17 100644 --- a/pkg/apiclient/api/openapi.yaml +++ b/pkg/apiclient/api/openapi.yaml @@ -67,6 +67,12 @@ paths: delete: description: Delete ALL builds operationId: DeleteAllBuilds + parameters: + - description: Force + in: query + name: force + schema: + type: boolean responses: "204": content: {} @@ -121,6 +127,11 @@ paths: required: true schema: type: string + - description: Force + in: query + name: force + schema: + type: boolean responses: "204": content: {} @@ -139,6 +150,11 @@ paths: required: true schema: type: string + - description: Force + in: query + name: force + schema: + type: boolean responses: "204": content: {} @@ -2567,6 +2583,7 @@ components: - success - published - pending-delete + - pending-forced-delete - deleting type: string x-enum-varnames: @@ -2576,6 +2593,7 @@ components: - BuildStateSuccess - BuildStatePublished - BuildStatePendingDelete + - BuildStatePendingForcedDelete - BuildStateDeleting provider.ProviderInfo: example: diff --git a/pkg/apiclient/api_build.go b/pkg/apiclient/api_build.go index bddf960f39..f3ed813ff3 100644 --- a/pkg/apiclient/api_build.go +++ b/pkg/apiclient/api_build.go @@ -151,6 +151,13 @@ func (a *BuildAPIService) CreateBuildExecute(r ApiCreateBuildRequest) (string, * type ApiDeleteAllBuildsRequest struct { ctx context.Context ApiService *BuildAPIService + force *bool +} + +// Force +func (r ApiDeleteAllBuildsRequest) Force(force bool) ApiDeleteAllBuildsRequest { + r.force = &force + return r } func (r ApiDeleteAllBuildsRequest) Execute() (*http.Response, error) { @@ -191,6 +198,9 @@ func (a *BuildAPIService) DeleteAllBuildsExecute(r ApiDeleteAllBuildsRequest) (* localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.force != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "force", r.force, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -254,6 +264,13 @@ type ApiDeleteBuildRequest struct { ctx context.Context ApiService *BuildAPIService buildId string + force *bool +} + +// Force +func (r ApiDeleteBuildRequest) Force(force bool) ApiDeleteBuildRequest { + r.force = &force + return r } func (r ApiDeleteBuildRequest) Execute() (*http.Response, error) { @@ -297,6 +314,9 @@ func (a *BuildAPIService) DeleteBuildExecute(r ApiDeleteBuildRequest) (*http.Res localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.force != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "force", r.force, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -360,6 +380,13 @@ type ApiDeleteBuildsFromPrebuildRequest struct { ctx context.Context ApiService *BuildAPIService prebuildId string + force *bool +} + +// Force +func (r ApiDeleteBuildsFromPrebuildRequest) Force(force bool) ApiDeleteBuildsFromPrebuildRequest { + r.force = &force + return r } func (r ApiDeleteBuildsFromPrebuildRequest) Execute() (*http.Response, error) { @@ -403,6 +430,9 @@ func (a *BuildAPIService) DeleteBuildsFromPrebuildExecute(r ApiDeleteBuildsFromP localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.force != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "force", r.force, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/pkg/apiclient/docs/BuildAPI.md b/pkg/apiclient/docs/BuildAPI.md index 6993bab86f..8c001f7e96 100644 --- a/pkg/apiclient/docs/BuildAPI.md +++ b/pkg/apiclient/docs/BuildAPI.md @@ -81,7 +81,7 @@ Name | Type | Description | Notes ## DeleteAllBuilds -> DeleteAllBuilds(ctx).Execute() +> DeleteAllBuilds(ctx).Force(force).Execute() Delete ALL builds @@ -100,10 +100,11 @@ import ( ) func main() { + force := true // bool | Force (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.BuildAPI.DeleteAllBuilds(context.Background()).Execute() + r, err := apiClient.BuildAPI.DeleteAllBuilds(context.Background()).Force(force).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.DeleteAllBuilds``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -113,13 +114,17 @@ func main() { ### Path Parameters -This endpoint does not need any parameter. + ### Other Parameters Other parameters are passed through a pointer to a apiDeleteAllBuildsRequest struct via the builder pattern +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **force** | **bool** | Force | + ### Return type (empty response body) @@ -140,7 +145,7 @@ Other parameters are passed through a pointer to a apiDeleteAllBuildsRequest str ## DeleteBuild -> DeleteBuild(ctx, buildId).Execute() +> DeleteBuild(ctx, buildId).Force(force).Execute() Delete build @@ -160,10 +165,11 @@ import ( func main() { buildId := "buildId_example" // string | Build ID + force := true // bool | Force (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.BuildAPI.DeleteBuild(context.Background(), buildId).Execute() + r, err := apiClient.BuildAPI.DeleteBuild(context.Background(), buildId).Force(force).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.DeleteBuild``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -187,6 +193,7 @@ Other parameters are passed through a pointer to a apiDeleteBuildRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **force** | **bool** | Force | ### Return type @@ -208,7 +215,7 @@ Name | Type | Description | Notes ## DeleteBuildsFromPrebuild -> DeleteBuildsFromPrebuild(ctx, prebuildId).Execute() +> DeleteBuildsFromPrebuild(ctx, prebuildId).Force(force).Execute() Delete builds @@ -228,10 +235,11 @@ import ( func main() { prebuildId := "prebuildId_example" // string | Prebuild ID + force := true // bool | Force (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.BuildAPI.DeleteBuildsFromPrebuild(context.Background(), prebuildId).Execute() + r, err := apiClient.BuildAPI.DeleteBuildsFromPrebuild(context.Background(), prebuildId).Force(force).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.DeleteBuildsFromPrebuild``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -255,6 +263,7 @@ Other parameters are passed through a pointer to a apiDeleteBuildsFromPrebuildRe Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **force** | **bool** | Force | ### Return type diff --git a/pkg/apiclient/docs/BuildBuildState.md b/pkg/apiclient/docs/BuildBuildState.md index e6baa25d2c..8a8b6a9b71 100644 --- a/pkg/apiclient/docs/BuildBuildState.md +++ b/pkg/apiclient/docs/BuildBuildState.md @@ -15,6 +15,8 @@ * `BuildStatePendingDelete` (value: `"pending-delete"`) +* `BuildStatePendingForcedDelete` (value: `"pending-forced-delete"`) + * `BuildStateDeleting` (value: `"deleting"`) diff --git a/pkg/apiclient/model_build_build_state.go b/pkg/apiclient/model_build_build_state.go index 5f9d6e76e6..c31c266c19 100644 --- a/pkg/apiclient/model_build_build_state.go +++ b/pkg/apiclient/model_build_build_state.go @@ -20,13 +20,14 @@ type BuildBuildState string // List of build.BuildState const ( - BuildStatePendingRun BuildBuildState = "pending-run" - BuildStateRunning BuildBuildState = "running" - BuildStateError BuildBuildState = "error" - BuildStateSuccess BuildBuildState = "success" - BuildStatePublished BuildBuildState = "published" - BuildStatePendingDelete BuildBuildState = "pending-delete" - BuildStateDeleting BuildBuildState = "deleting" + BuildStatePendingRun BuildBuildState = "pending-run" + BuildStateRunning BuildBuildState = "running" + BuildStateError BuildBuildState = "error" + BuildStateSuccess BuildBuildState = "success" + BuildStatePublished BuildBuildState = "published" + BuildStatePendingDelete BuildBuildState = "pending-delete" + BuildStatePendingForcedDelete BuildBuildState = "pending-forced-delete" + BuildStateDeleting BuildBuildState = "deleting" ) // All allowed values of BuildBuildState enum @@ -37,6 +38,7 @@ var AllowedBuildBuildStateEnumValues = []BuildBuildState{ "success", "published", "pending-delete", + "pending-forced-delete", "deleting", } diff --git a/pkg/build/build.go b/pkg/build/build.go index e90bbe8562..a21d34a2d0 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -16,13 +16,14 @@ import ( type BuildState string const ( - BuildStatePendingRun BuildState = "pending-run" - BuildStateRunning BuildState = "running" - BuildStateError BuildState = "error" - BuildStateSuccess BuildState = "success" - BuildStatePublished BuildState = "published" - BuildStatePendingDelete BuildState = "pending-delete" - BuildStateDeleting BuildState = "deleting" + BuildStatePendingRun BuildState = "pending-run" + BuildStateRunning BuildState = "running" + BuildStateError BuildState = "error" + BuildStateSuccess BuildState = "success" + BuildStatePublished BuildState = "published" + BuildStatePendingDelete BuildState = "pending-delete" + BuildStatePendingForcedDelete BuildState = "pending-forced-delete" + BuildStateDeleting BuildState = "deleting" ) type Build struct { diff --git a/pkg/build/runner.go b/pkg/build/runner.go index 773fbae1ad..b81ae73e8d 100644 --- a/pkg/build/runner.go +++ b/pkg/build/runner.go @@ -172,7 +172,7 @@ func (r *BuildRunner) RunBuilds() { func (r *BuildRunner) DeleteBuilds() { markedForDeletionBuilds, err := r.buildStore.List(&Filter{ - States: &[]BuildState{BuildStatePendingDelete}, + States: &[]BuildState{BuildStatePendingDelete, BuildStatePendingForcedDelete}, }) if err != nil { log.Error(err) @@ -197,6 +197,8 @@ func (r *BuildRunner) DeleteBuilds() { buildLogger := r.loggerFactory.CreateBuildLogger(b.Id, logs.LogSourceBuilder) defer buildLogger.Close() + force := b.State == BuildStatePendingForcedDelete + b.State = BuildStateDeleting err = r.buildStore.Save(b) if err != nil { @@ -209,7 +211,9 @@ func (r *BuildRunner) DeleteBuilds() { err := dockerClient.DeleteImage(*b.Image, true, nil) if err != nil { r.handleBuildError(*b, nil, err, buildLogger) - return + if !force { + return + } } } diff --git a/pkg/cmd/build/delete.go b/pkg/cmd/build/delete.go index 4243a0394f..509626c66c 100644 --- a/pkg/cmd/build/delete.go +++ b/pkg/cmd/build/delete.go @@ -29,22 +29,22 @@ var buildDeleteCmd = &cobra.Command{ } if allFlag { - res, err := apiClient.BuildAPI.DeleteAllBuilds(ctx).Execute() + res, err := apiClient.BuildAPI.DeleteAllBuilds(ctx).Force(forceFlag).Execute() if err != nil { log.Fatal(apiclient_util.HandleErrorResponse(res, err)) } - views.RenderInfoMessage("All builds deleted successfully") + views.RenderInfoMessage("All builds have been marked for deletion") return } if prebuildIdFlag != "" { - res, err := apiClient.BuildAPI.DeleteBuildsFromPrebuild(ctx, prebuildIdFlag).Execute() + res, err := apiClient.BuildAPI.DeleteBuildsFromPrebuild(ctx, prebuildIdFlag).Force(forceFlag).Execute() if err != nil { log.Fatal(apiclient_util.HandleErrorResponse(res, err)) } - views.RenderInfoMessage(fmt.Sprintf("All builds from prebuild %s deleted\n", prebuildIdFlag)) + views.RenderInfoMessage(fmt.Sprintf("All builds from prebuild %s have been marked for deletion\n", prebuildIdFlag)) return } @@ -63,18 +63,20 @@ var buildDeleteCmd = &cobra.Command{ buildId = args[0] } - res, err := apiClient.BuildAPI.DeleteBuild(ctx, buildId).Execute() + res, err := apiClient.BuildAPI.DeleteBuild(ctx, buildId).Force(forceFlag).Execute() if err != nil { log.Fatal(apiclient_util.HandleErrorResponse(res, err)) } - views.RenderInfoMessage(fmt.Sprintf("Build %s deleted successfully", buildId)) + views.RenderInfoMessage(fmt.Sprintf("Build %s has been marked for deletion", buildId)) }, } var allFlag bool +var forceFlag bool var prebuildIdFlag string func init() { buildDeleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete ALL builds") + buildDeleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete build") buildDeleteCmd.Flags().StringVar(&prebuildIdFlag, "prebuild-id", "", "Delete ALL builds from prebuild") } diff --git a/pkg/server/builds/service.go b/pkg/server/builds/service.go index 9e0e3e6076..1681ec6386 100644 --- a/pkg/server/builds/service.go +++ b/pkg/server/builds/service.go @@ -19,7 +19,7 @@ type IBuildService interface { Create(dto.BuildCreationData) (string, error) Find(filter *build.Filter) (*build.Build, error) List(filter *build.Filter) ([]*build.Build, error) - MarkForDeletion(filter *build.Filter) []error + MarkForDeletion(filter *build.Filter, force bool) []error Delete(id string) error AwaitEmptyList(time.Duration) error GetBuildLogReader(buildId string) (io.Reader, error) @@ -75,7 +75,7 @@ func (s *BuildService) List(filter *build.Filter) ([]*build.Build, error) { return s.buildStore.List(filter) } -func (s *BuildService) MarkForDeletion(filter *build.Filter) []error { +func (s *BuildService) MarkForDeletion(filter *build.Filter, force bool) []error { var errors []error builds, err := s.List(filter) @@ -84,7 +84,12 @@ func (s *BuildService) MarkForDeletion(filter *build.Filter) []error { } for _, b := range builds { - b.State = build.BuildStatePendingDelete + if force { + b.State = build.BuildStatePendingForcedDelete + } else { + b.State = build.BuildStatePendingDelete + } + err = s.buildStore.Save(b) if err != nil { errors = append(errors, err) diff --git a/pkg/server/builds/service_test.go b/pkg/server/builds/service_test.go index d5fda4d23b..4124b85613 100644 --- a/pkg/server/builds/service_test.go +++ b/pkg/server/builds/service_test.go @@ -168,7 +168,7 @@ func (s *BuildServiceTestSuite) TestMarkForDeletion() { err := s.buildService.MarkForDeletion(&build.Filter{ Id: &build3.Id, - }) + }, false) require.Nil(err) b, errs := s.buildService.Find(&build.Filter{ diff --git a/pkg/server/projectconfig/prebuild.go b/pkg/server/projectconfig/prebuild.go index 9b5e1523af..42e5f4b5d6 100644 --- a/pkg/server/projectconfig/prebuild.go +++ b/pkg/server/projectconfig/prebuild.go @@ -205,7 +205,7 @@ func (s *ProjectConfigService) DeletePrebuild(projectConfigName string, id strin errs := s.buildService.MarkForDeletion(&build.Filter{ PrebuildIds: &[]string{id}, - }) + }, force) if len(errs) > 0 { if force { for _, err := range errs { @@ -370,7 +370,7 @@ func (s *ProjectConfigService) EnforceRetentionPolicy() error { for i := 0; i < numToDelete; i++ { errs := s.buildService.MarkForDeletion(&build.Filter{ Id: &associatedBuilds[i].Id, - }) + }, false) if len(errs) > 0 { for _, err := range errs { log.Error(err) diff --git a/pkg/server/projectconfig/prebuild_test.go b/pkg/server/projectconfig/prebuild_test.go index 989f67ce48..d780a30186 100644 --- a/pkg/server/projectconfig/prebuild_test.go +++ b/pkg/server/projectconfig/prebuild_test.go @@ -113,7 +113,7 @@ func (s *ProjectConfigServiceTestSuite) TestDeletePrebuild() { s.buildService.On("MarkForDeletion", &build.Filter{ PrebuildIds: &[]string{prebuild2.Id}, - }).Return([]error{}) + }, false).Return([]error{}) err := s.projectConfigService.DeletePrebuild(projectConfig1.Name, prebuild2.Id, false) require.Nil(err) @@ -228,7 +228,7 @@ func (s *ProjectConfigServiceTestSuite) TestEnforceRetentionPolicy() { s.buildService.On("MarkForDeletion", &build.Filter{ Id: util.Pointer("1"), - }).Return([]error{}) + }, false).Return([]error{}) err := s.projectConfigService.EnforceRetentionPolicy() require.Nil(err) diff --git a/pkg/server/purge.go b/pkg/server/purge.go index 1ad6c79881..eeb764f2e9 100644 --- a/pkg/server/purge.go +++ b/pkg/server/purge.go @@ -100,7 +100,7 @@ func (s *Server) Purge(ctx context.Context, force bool) []error { } fmt.Println("Purging builds...") - errs := s.BuildService.MarkForDeletion(nil) + errs := s.BuildService.MarkForDeletion(nil, force) if len(errs) > 0 { s.trackPurgeError(ctx, force, errs[0]) if !force {