Skip to content

Commit 987e24b

Browse files
feat: add remaining VCS integrations (#98)
What - Added support for 3 additional version control system integrations to the Spacelift Terraform module: GitLab, Bitbucket Cloud, and Bitbucket Data Center - Added dynamic blocks in main.tf for each new VCS integration following the same pattern as existing integrations - Added tests for all VCS integrations - Mock the spacelift provider for the VCS specific tests. Why - All VCSs in the provider are now supported in the module References - https://registry.terraform.io/providers/spacelift-io/spacelift/latest/docs/resources/stack - https://docs.spacelift.io/integrations/source-control/ - https://docs.spacelift.io/integrations/source-control/gitlab - https://docs.spacelift.io/integrations/source-control/bitbucket-cloud - https://docs.spacelift.io/integrations/source-control/bitbucket-datacenter-server <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added optional inputs to configure GitLab, Bitbucket Cloud, and Bitbucket Data Center integrations for stacks. Non-breaking: if not provided, behavior is unchanged. * **Documentation** * Updated README to describe the new integration inputs, including fields and defaults. * **Tests** * Added test coverage to validate configuration of GitLab, Bitbucket Cloud, and Bitbucket Data Center integrations and ensure blocks remain empty when inputs are null. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 3b9c795 commit 987e24b

File tree

4 files changed

+236
-0
lines changed

4 files changed

+236
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ If you have many remote repositories that you need to manage via this pattern, y
360360
| <a name="input_before_init"></a> [before\_init](#input\_before\_init) | List of before-init scripts | `list(string)` | `[]` | no |
361361
| <a name="input_before_perform"></a> [before\_perform](#input\_before\_perform) | List of before-perform scripts | `list(string)` | `[]` | no |
362362
| <a name="input_before_plan"></a> [before\_plan](#input\_before\_plan) | List of before-plan scripts | `list(string)` | `[]` | no |
363+
| <a name="input_bitbucket_cloud"></a> [bitbucket\_cloud](#input\_bitbucket\_cloud) | The Bitbucket Cloud integration settings | <pre>object({<br/> namespace = string<br/> id = optional(string)<br/> })</pre> | `null` | no |
364+
| <a name="input_bitbucket_datacenter"></a> [bitbucket\_datacenter](#input\_bitbucket\_datacenter) | The Bitbucket Data Center integration settings | <pre>object({<br/> namespace = string<br/> id = optional(string)<br/> })</pre> | `null` | no |
363365
| <a name="input_branch"></a> [branch](#input\_branch) | Specify which branch to use within the infrastructure repository. | `string` | `"main"` | no |
364366
| <a name="input_common_config_file"></a> [common\_config\_file](#input\_common\_config\_file) | Name of the common configuration file for the stack across a root module. | `string` | `"common.yaml"` | no |
365367
| <a name="input_default_tf_workspace_enabled"></a> [default\_tf\_workspace\_enabled](#input\_default\_tf\_workspace\_enabled) | Enables the use of `default` Terraform workspace instead of managing multiple workspaces within a root module.<br/><br/>NOTE: We encourage the use of Terraform workspaces to manage multiple environments.<br/>However, you will want to disable this behavior if you're utilizing different backends for each instance<br/>of your root modules (we call this "Dynamic Backends"). | `bool` | `false` | no |
@@ -376,6 +378,7 @@ If you have many remote repositories that you need to manage via this pattern, y
376378
| <a name="input_enabled_root_modules"></a> [enabled\_root\_modules](#input\_enabled\_root\_modules) | List of root modules where to look for stack config files.<br/>Ignored when all\_root\_modules\_enabled is true.<br/>Example: ["spacelift-automation", "k8s-cluster"] | `list(string)` | `[]` | no |
377379
| <a name="input_github_action_deploy"></a> [github\_action\_deploy](#input\_github\_action\_deploy) | Indicates whether GitHub users can deploy from the Checks API. | `bool` | `true` | no |
378380
| <a name="input_github_enterprise"></a> [github\_enterprise](#input\_github\_enterprise) | The GitHub VCS settings | <pre>object({<br/> namespace = string<br/> id = optional(string)<br/> })</pre> | `null` | no |
381+
| <a name="input_gitlab"></a> [gitlab](#input\_gitlab) | The GitLab integration settings | <pre>object({<br/> namespace = string<br/> id = optional(string)<br/> })</pre> | `null` | no |
379382
| <a name="input_labels"></a> [labels](#input\_labels) | List of labels to apply to the stacks. | `list(string)` | `[]` | no |
380383
| <a name="input_manage_state"></a> [manage\_state](#input\_manage\_state) | Determines if Spacelift should manage state for this stack. | `bool` | `false` | no |
381384
| <a name="input_protect_from_deletion"></a> [protect\_from\_deletion](#input\_protect\_from\_deletion) | Protect this stack from accidental deletion. If set, attempts to delete this stack will fail. | `bool` | `false` | no |

main.tf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,30 @@ resource "spacelift_stack" "default" {
508508
url = raw_git.value["url"]
509509
}
510510
}
511+
512+
dynamic "gitlab" {
513+
for_each = var.gitlab != null ? [var.gitlab] : []
514+
content {
515+
namespace = gitlab.value["namespace"]
516+
id = try(gitlab.value["id"], null)
517+
}
518+
}
519+
520+
dynamic "bitbucket_cloud" {
521+
for_each = var.bitbucket_cloud != null ? [var.bitbucket_cloud] : []
522+
content {
523+
namespace = bitbucket_cloud.value["namespace"]
524+
id = try(bitbucket_cloud.value["id"], null)
525+
}
526+
}
527+
528+
dynamic "bitbucket_datacenter" {
529+
for_each = var.bitbucket_datacenter != null ? [var.bitbucket_datacenter] : []
530+
content {
531+
namespace = bitbucket_datacenter.value["namespace"]
532+
id = try(bitbucket_datacenter.value["id"], null)
533+
}
534+
}
511535
}
512536

513537
# The Spacelift Destructor is a feature designed to automatically clean up the resources no longer managed by our IaC.

tests/vcs_integrations.tftest.hcl

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
mock_provider "spacelift" {
2+
mock_data "spacelift_spaces" {
3+
defaults = {
4+
spaces = []
5+
}
6+
}
7+
8+
mock_data "spacelift_worker_pools" {
9+
defaults = {
10+
worker_pools = []
11+
}
12+
}
13+
14+
mock_data "spacelift_aws_integrations" {
15+
defaults = {
16+
integrations = []
17+
}
18+
}
19+
}
20+
21+
mock_provider "jsonschema" {
22+
mock_data "jsonschema_validator" {
23+
defaults = {
24+
validated = "{}"
25+
}
26+
}
27+
}
28+
29+
variables {
30+
root_modules_path = "./tests/fixtures/multi-instance"
31+
common_config_file = "common.yaml"
32+
repository = "terraform-spacelift-automation"
33+
all_root_modules_enabled = true
34+
aws_integration_enabled = false
35+
}
36+
37+
# Test gitlab dynamic block is created correctly
38+
run "test_gitlab_integration_id_is_null" {
39+
command = plan
40+
41+
variables {
42+
gitlab = {
43+
namespace = "my-gitlab-group"
44+
}
45+
}
46+
47+
assert {
48+
condition = spacelift_stack.default["root-module-a-test"].gitlab[0].namespace == "my-gitlab-group"
49+
error_message = "GitLab namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].gitlab)}"
50+
}
51+
52+
assert {
53+
condition = spacelift_stack.default["root-module-a-test"].gitlab[0].id == null
54+
error_message = "GitLab id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].gitlab)}"
55+
}
56+
}
57+
58+
# Test github_enterprise dynamic block is created correctly
59+
run "test_github_enterprise_integration" {
60+
command = plan
61+
62+
variables {
63+
github_enterprise = {
64+
namespace = "masterpointio"
65+
id = "test-gh-enterprise-id"
66+
}
67+
}
68+
69+
assert {
70+
condition = spacelift_stack.default["root-module-a-test"].github_enterprise[0].namespace == "masterpointio"
71+
error_message = "GitHub Enterprise namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].github_enterprise)}"
72+
}
73+
74+
assert {
75+
condition = spacelift_stack.default["root-module-a-test"].github_enterprise[0].id == "test-gh-enterprise-id"
76+
error_message = "GitHub Enterprise id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].github_enterprise)}"
77+
}
78+
}
79+
80+
# Test raw_git dynamic block is created correctly
81+
run "test_raw_git_integration" {
82+
command = plan
83+
84+
variables {
85+
raw_git = {
86+
namespace = "my-git-namespace"
87+
url = "https://git.example.com/repo.git"
88+
}
89+
}
90+
91+
assert {
92+
condition = spacelift_stack.default["root-module-a-test"].raw_git[0].namespace == "my-git-namespace"
93+
error_message = "Raw Git namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].raw_git)}"
94+
}
95+
96+
assert {
97+
condition = spacelift_stack.default["root-module-a-test"].raw_git[0].url == "https://git.example.com/repo.git"
98+
error_message = "Raw Git url was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].raw_git)}"
99+
}
100+
}
101+
102+
# Test bitbucket_cloud dynamic block is created correctly
103+
run "test_bitbucket_cloud_integration" {
104+
command = plan
105+
106+
variables {
107+
bitbucket_cloud = {
108+
namespace = "my-bitbucket-project"
109+
id = "test-bb-cloud-id"
110+
}
111+
}
112+
113+
assert {
114+
condition = spacelift_stack.default["root-module-a-test"].bitbucket_cloud[0].namespace == "my-bitbucket-project"
115+
error_message = "Bitbucket Cloud namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_cloud)}"
116+
}
117+
118+
assert {
119+
condition = spacelift_stack.default["root-module-a-test"].bitbucket_cloud[0].id == "test-bb-cloud-id"
120+
error_message = "Bitbucket Cloud id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_cloud)}"
121+
}
122+
}
123+
124+
# Test bitbucket_datacenter dynamic block is created correctly
125+
run "test_bitbucket_datacenter_integration" {
126+
command = plan
127+
128+
variables {
129+
bitbucket_datacenter = {
130+
namespace = "my-bitbucket-dc-project"
131+
id = "test-bb-dc-id"
132+
}
133+
}
134+
135+
assert {
136+
condition = spacelift_stack.default["root-module-a-test"].bitbucket_datacenter[0].namespace == "my-bitbucket-dc-project"
137+
error_message = "Bitbucket Data Center namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter)}"
138+
}
139+
140+
assert {
141+
condition = spacelift_stack.default["root-module-a-test"].bitbucket_datacenter[0].id == "test-bb-dc-id"
142+
error_message = "Bitbucket Data Center id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter)}"
143+
}
144+
}
145+
146+
# Test that VCS blocks are empty when variables are null
147+
run "test_vcs_blocks_empty_when_null" {
148+
command = plan
149+
150+
variables {
151+
github_enterprise = null
152+
raw_git = null
153+
gitlab = null
154+
bitbucket_cloud = null
155+
bitbucket_datacenter = null
156+
}
157+
158+
assert {
159+
condition = length(spacelift_stack.default["root-module-a-test"].github_enterprise) == 0
160+
error_message = "GitHub Enterprise block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].github_enterprise)}"
161+
}
162+
163+
assert {
164+
condition = length(spacelift_stack.default["root-module-a-test"].raw_git) == 0
165+
error_message = "Raw Git block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].raw_git)}"
166+
}
167+
168+
assert {
169+
condition = length(spacelift_stack.default["root-module-a-test"].gitlab) == 0
170+
error_message = "GitLab block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].gitlab)}"
171+
}
172+
173+
assert {
174+
condition = length(spacelift_stack.default["root-module-a-test"].bitbucket_cloud) == 0
175+
error_message = "Bitbucket Cloud block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_cloud)}"
176+
}
177+
178+
assert {
179+
condition = length(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter) == 0
180+
error_message = "Bitbucket Data Center block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter)}"
181+
}
182+
}

variables.tf

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,33 @@ variable "raw_git" {
5454
default = null
5555
}
5656

57+
variable "gitlab" {
58+
type = object({
59+
namespace = string
60+
id = optional(string)
61+
})
62+
description = "The GitLab integration settings"
63+
default = null
64+
}
65+
66+
variable "bitbucket_cloud" {
67+
type = object({
68+
namespace = string
69+
id = optional(string)
70+
})
71+
description = "The Bitbucket Cloud integration settings"
72+
default = null
73+
}
74+
75+
variable "bitbucket_datacenter" {
76+
type = object({
77+
namespace = string
78+
id = optional(string)
79+
})
80+
description = "The Bitbucket Data Center integration settings"
81+
default = null
82+
}
83+
5784

5885
variable "repository" {
5986
type = string

0 commit comments

Comments
 (0)