Skip to content

Commit be59cd1

Browse files
authored
Merge pull request #816 from timofurrer/feature/archive-on-destroy-761
Implement `archive_on_destroy` attribute for projects. Closes #761
2 parents 4d2d649 + 8f6754b commit be59cd1

File tree

3 files changed

+126
-30
lines changed

3 files changed

+126
-30
lines changed

docs/resources/project.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ resource "gitlab_project" "example-two" {
4444

4545
- **allow_merge_on_skipped_pipeline** (Boolean) Set to true if you want to treat skipped pipelines as if they finished with success.
4646
- **approvals_before_merge** (Number) Number of merge request approvals required for merging. Default is 0.
47+
- **archive_on_destroy** (Boolean) Set to `true` to archive the project instead of deleting on destroy. If set to `true` it will entire omit the `DELETE` operation.
4748
- **archived** (Boolean) Whether the project is in read-only mode (archived). Repositories can be archived/unarchived by toggling this parameter.
4849
- **build_coverage_regex** (String) Test coverage parsing for the project.
4950
- **ci_config_path** (String) Custom Path to CI config file.

gitlab/resource_gitlab_project.go

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ var resourceGitLabProjectSchema = map[string]*schema.Schema{
358358
Type: schema.TypeString,
359359
Optional: true,
360360
},
361+
"archive_on_destroy": {
362+
Description: "Set to `true` to archive the project instead of deleting on destroy. If set to `true` it will entire omit the `DELETE` operation.",
363+
Type: schema.TypeBool,
364+
Optional: true,
365+
},
361366
}
362367

363368
func resourceGitlabProject() *schema.Resource {
@@ -857,43 +862,53 @@ func resourceGitlabProjectUpdate(ctx context.Context, d *schema.ResourceData, me
857862

858863
func resourceGitlabProjectDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
859864
client := meta.(*gitlab.Client)
860-
log.Printf("[DEBUG] Delete gitlab project %s", d.Id())
861865

862-
_, err := client.Projects.DeleteProject(d.Id(), gitlab.WithContext(ctx))
863-
if err != nil {
864-
return diag.FromErr(err)
865-
}
866+
if !d.Get("archive_on_destroy").(bool) {
867+
log.Printf("[DEBUG] Delete gitlab project %s", d.Id())
868+
_, err := client.Projects.DeleteProject(d.Id(), gitlab.WithContext(ctx))
869+
if err != nil {
870+
return diag.FromErr(err)
871+
}
866872

867-
// Wait for the project to be deleted.
868-
// Deleting a project in gitlab is async.
869-
stateConf := &resource.StateChangeConf{
870-
Pending: []string{"Deleting"},
871-
Target: []string{"Deleted"},
872-
Refresh: func() (interface{}, string, error) {
873-
out, response, err := client.Projects.GetProject(d.Id(), nil, gitlab.WithContext(ctx))
874-
if err != nil {
875-
if response.StatusCode == 404 {
873+
// Wait for the project to be deleted.
874+
// Deleting a project in gitlab is async.
875+
stateConf := &resource.StateChangeConf{
876+
Pending: []string{"Deleting"},
877+
Target: []string{"Deleted"},
878+
Refresh: func() (interface{}, string, error) {
879+
out, response, err := client.Projects.GetProject(d.Id(), nil, gitlab.WithContext(ctx))
880+
if err != nil {
881+
if response.StatusCode == 404 {
882+
return out, "Deleted", nil
883+
}
884+
log.Printf("[ERROR] Received error: %#v", err)
885+
return out, "Error", err
886+
}
887+
if out.MarkedForDeletionAt != nil {
888+
// Represents a Gitlab EE soft-delete
876889
return out, "Deleted", nil
877890
}
878-
log.Printf("[ERROR] Received error: %#v", err)
879-
return out, "Error", err
880-
}
881-
if out.MarkedForDeletionAt != nil {
882-
// Represents a Gitlab EE soft-delete
883-
return out, "Deleted", nil
884-
}
885-
return out, "Deleting", nil
886-
},
891+
return out, "Deleting", nil
892+
},
887893

888-
Timeout: 10 * time.Minute,
889-
MinTimeout: 3 * time.Second,
890-
Delay: 5 * time.Second,
891-
}
894+
Timeout: 10 * time.Minute,
895+
MinTimeout: 3 * time.Second,
896+
Delay: 5 * time.Second,
897+
}
892898

893-
_, err = stateConf.WaitForStateContext(ctx)
894-
if err != nil {
895-
return diag.Errorf("error waiting for project (%s) to become deleted: %s", d.Id(), err)
899+
_, err = stateConf.WaitForStateContext(ctx)
900+
if err != nil {
901+
return diag.Errorf("error waiting for project (%s) to become deleted: %s", d.Id(), err)
902+
}
903+
904+
} else {
905+
log.Printf("[DEBUG] Archive gitlab project %s", d.Id())
906+
_, _, err := client.Projects.ArchiveProject(d.Id(), gitlab.WithContext(ctx))
907+
if err != nil {
908+
return diag.FromErr(err)
909+
}
896910
}
911+
897912
return nil
898913
}
899914

gitlab/resource_gitlab_project_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,21 @@ func TestAccGitlabProject_initializeWithoutReadme(t *testing.T) {
383383
})
384384
}
385385

386+
func TestAccGitlabProject_archiveOnDestroy(t *testing.T) {
387+
rInt := acctest.RandInt()
388+
389+
resource.Test(t, resource.TestCase{
390+
PreCheck: func() { testAccPreCheck(t) },
391+
Providers: testAccProviders,
392+
CheckDestroy: testAccCheckGitlabProjectArchivedOnDestroy,
393+
Steps: []resource.TestStep{
394+
{
395+
Config: testAccGitlabProjectConfigArchiveOnDestroy(rInt),
396+
},
397+
},
398+
})
399+
}
400+
386401
func TestAccGitlabProject_IssueMergeRequestTemplates(t *testing.T) {
387402
var project gitlab.Project
388403
rInt := acctest.RandInt()
@@ -881,6 +896,27 @@ func testAccCheckGitlabProjectDestroy(s *terraform.State) error {
881896
return nil
882897
}
883898

899+
func testAccCheckGitlabProjectArchivedOnDestroy(s *terraform.State) error {
900+
conn := testAccProvider.Meta().(*gitlab.Client)
901+
for _, rs := range s.RootModule().Resources {
902+
if rs.Type != "gitlab_project" {
903+
continue
904+
}
905+
906+
gotRepo, _, err := conn.Projects.GetProject(rs.Primary.ID, nil)
907+
if err != nil {
908+
return fmt.Errorf("unable to get project %s, to check if it has been archived on the destroy", rs.Primary.ID)
909+
}
910+
911+
if !gotRepo.Archived {
912+
return fmt.Errorf("expected project to be archived, but it isn't")
913+
}
914+
return nil
915+
}
916+
917+
return fmt.Errorf("no project resources found in state, but expected a `gitlab_project` resource marked as archvied")
918+
}
919+
884920
func testAccCheckAggregateGitlabProject(expected, received *gitlab.Project) resource.TestCheckFunc {
885921
var checks []resource.TestCheckFunc
886922

@@ -1174,6 +1210,10 @@ resource "gitlab_project" "foo" {
11741210
path = "foo.%d"
11751211
description = "Terraform acceptance tests"
11761212
initialize_with_readme = true
1213+
1214+
# So that acceptance tests can be run in a gitlab organization
1215+
# with no billing
1216+
visibility_level = "public"
11771217
}
11781218
`, rInt, rInt)
11791219
}
@@ -1185,6 +1225,10 @@ resource "gitlab_project" "foo" {
11851225
path = "foo.%d"
11861226
description = "Terraform acceptance tests"
11871227
initialize_with_readme = false
1228+
1229+
# So that acceptance tests can be run in a gitlab organization
1230+
# with no billing
1231+
visibility_level = "public"
11881232
}
11891233
`, rInt, rInt)
11901234
}
@@ -1282,6 +1326,10 @@ resource "gitlab_project" "template-name" {
12821326
description = "Terraform acceptance tests"
12831327
template_name = "rails"
12841328
default_branch = "master"
1329+
1330+
# So that acceptance tests can be run in a gitlab organization
1331+
# with no billing
1332+
visibility_level = "public"
12851333
}
12861334
`, rInt, rInt)
12871335
}
@@ -1301,6 +1349,10 @@ resource "gitlab_project" "template-name-custom" {
13011349
template_name = "myrails"
13021350
use_custom_template = true
13031351
default_branch = "master"
1352+
1353+
# So that acceptance tests can be run in a gitlab organization
1354+
# with no billing
1355+
visibility_level = "public"
13041356
}
13051357
`, rInt, rInt)
13061358
}
@@ -1314,6 +1366,10 @@ resource "gitlab_project" "template-id" {
13141366
template_project_id = 999
13151367
use_custom_template = true
13161368
default_branch = "master"
1369+
1370+
# So that acceptance tests can be run in a gitlab organization
1371+
# with no billing
1372+
visibility_level = "public"
13171373
}
13181374
`, rInt, rInt)
13191375
}
@@ -1328,6 +1384,10 @@ resource "gitlab_project" "template-mutual-exclusive" {
13281384
template_project_id = 999
13291385
use_custom_template = true
13301386
default_branch = "master"
1387+
1388+
# So that acceptance tests can be run in a gitlab organization
1389+
# with no billing
1390+
visibility_level = "public"
13311391
}
13321392
`, rInt, rInt)
13331393
}
@@ -1340,6 +1400,26 @@ resource "gitlab_project" "foo" {
13401400
description = "Terraform acceptance tests"
13411401
issues_template = "foo"
13421402
merge_requests_template = "bar"
1403+
1404+
# So that acceptance tests can be run in a gitlab organization
1405+
# with no billing
1406+
visibility_level = "public"
1407+
}
1408+
`, rInt, rInt)
1409+
}
1410+
1411+
func testAccGitlabProjectConfigArchiveOnDestroy(rInt int) string {
1412+
return fmt.Sprintf(`
1413+
resource "gitlab_project" "foo" {
1414+
name = "foo-%d"
1415+
path = "foo.%d"
1416+
description = "Terraform acceptance tests"
1417+
archive_on_destroy = true
1418+
archived = false
1419+
1420+
# So that acceptance tests can be run in a gitlab organization
1421+
# with no billing
1422+
visibility_level = "public"
13431423
}
13441424
`, rInt, rInt)
13451425
}

0 commit comments

Comments
 (0)