Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ If you have many remote repositories that you need to manage via this pattern, y
| <a name="input_before_init"></a> [before\_init](#input\_before\_init) | List of before-init scripts | `list(string)` | `[]` | no |
| <a name="input_before_perform"></a> [before\_perform](#input\_before\_perform) | List of before-perform scripts | `list(string)` | `[]` | no |
| <a name="input_before_plan"></a> [before\_plan](#input\_before\_plan) | List of before-plan scripts | `list(string)` | `[]` | no |
| <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 |
| <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 |
| <a name="input_branch"></a> [branch](#input\_branch) | Specify which branch to use within the infrastructure repository. | `string` | `"main"` | no |
| <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 |
| <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 |
Expand All @@ -376,6 +378,7 @@ If you have many remote repositories that you need to manage via this pattern, y
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_labels"></a> [labels](#input\_labels) | List of labels to apply to the stacks. | `list(string)` | `[]` | no |
| <a name="input_manage_state"></a> [manage\_state](#input\_manage\_state) | Determines if Spacelift should manage state for this stack. | `bool` | `false` | no |
| <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 |
Expand Down
24 changes: 24 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,30 @@ resource "spacelift_stack" "default" {
url = raw_git.value["url"]
}
}

dynamic "gitlab" {
for_each = var.gitlab != null ? [var.gitlab] : []
content {
namespace = gitlab.value["namespace"]
id = try(gitlab.value["id"], null)
}
}

dynamic "bitbucket_cloud" {
for_each = var.bitbucket_cloud != null ? [var.bitbucket_cloud] : []
content {
namespace = bitbucket_cloud.value["namespace"]
id = try(bitbucket_cloud.value["id"], null)
}
}

dynamic "bitbucket_datacenter" {
for_each = var.bitbucket_datacenter != null ? [var.bitbucket_datacenter] : []
content {
namespace = bitbucket_datacenter.value["namespace"]
id = try(bitbucket_datacenter.value["id"], null)
}
}
}

# The Spacelift Destructor is a feature designed to automatically clean up the resources no longer managed by our IaC.
Expand Down
183 changes: 183 additions & 0 deletions tests/vcs_integrations.tftest.hcl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks good. Hmm I'm just thinking about the tests. I'm not sure how much to justify it because it is mostly just declarative (as there's not much to test, just that namespace = github.lab["namespace"], and it's the same for GitHub, BitBucket, etc. Since the code is kinda just replicating the Terraform Spacelift provider directly, it's not really validating anything I'm thinking?

I guess it doesn't hurt and it's easy to generate, prevents breaking things in the future?

What are your thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a similar question. I think there are 2 things worth testing,

  1. That a human correctly added a dynamic around each VCS block blocks
  2. That the optional id field is correctly handled (see the test_gitlab_integration_id_is_null test)

Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
mock_provider "spacelift" {
mock_data "spacelift_spaces" {
defaults = {
spaces = []
}
}

mock_data "spacelift_worker_pools" {
defaults = {
worker_pools = []
}
}

mock_data "spacelift_aws_integrations" {
defaults = {
integrations = []
}
}
}

mock_provider "jsonschema" {
mock_data "jsonschema_validator" {
defaults = {
validated = "{}"
}
}
}

variables {
root_modules_path = "./tests/fixtures/multi-instance"
common_config_file = "common.yaml"
repository = "terraform-spacelift-automation"
all_root_modules_enabled = true
aws_integration_enabled = false
}

# Test github_enterprise dynamic block is created correctly
run "test_github_enterprise_integration" {
command = plan

variables {
github_enterprise = {
namespace = "masterpointio"
id = "test-gh-enterprise-id"
}
}

assert {
condition = spacelift_stack.default["root-module-a-test"].github_enterprise[0].namespace == "masterpointio"
error_message = "GitHub Enterprise namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].github_enterprise)}"
}

assert {
condition = spacelift_stack.default["root-module-a-test"].github_enterprise[0].id == "test-gh-enterprise-id"
error_message = "GitHub Enterprise id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].github_enterprise)}"
}
}

# Test raw_git dynamic block is created correctly
run "test_raw_git_integration" {
command = plan

variables {
raw_git = {
namespace = "my-git-namespace"
url = "https://git.example.com/repo.git"
}
}

assert {
condition = spacelift_stack.default["root-module-a-test"].raw_git[0].namespace == "my-git-namespace"
error_message = "Raw Git namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].raw_git)}"
}

assert {
condition = spacelift_stack.default["root-module-a-test"].raw_git[0].url == "https://git.example.com/repo.git"
error_message = "Raw Git url was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].raw_git)}"
}
}

# Test gitlab dynamic block is created correctly
run "test_gitlab_integration" {
command = plan

variables {
gitlab = {
namespace = "my-gitlab-group"
id = "test-gitlab-id"
}
}

assert {
condition = spacelift_stack.default["root-module-a-test"].gitlab[0].namespace == "my-gitlab-group"
error_message = "GitLab namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].gitlab)}"
}

assert {
condition = spacelift_stack.default["root-module-a-test"].gitlab[0].id == "test-gitlab-id"
error_message = "GitLab id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].gitlab)}"
}
}

# Test bitbucket_cloud dynamic block is created correctly
run "test_bitbucket_cloud_integration" {
command = plan

variables {
bitbucket_cloud = {
namespace = "my-bitbucket-project"
id = "test-bb-cloud-id"
}
}

assert {
condition = spacelift_stack.default["root-module-a-test"].bitbucket_cloud[0].namespace == "my-bitbucket-project"
error_message = "Bitbucket Cloud namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_cloud)}"
}

assert {
condition = spacelift_stack.default["root-module-a-test"].bitbucket_cloud[0].id == "test-bb-cloud-id"
error_message = "Bitbucket Cloud id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_cloud)}"
}
}

# Test bitbucket_datacenter dynamic block is created correctly
run "test_bitbucket_datacenter_integration" {
command = plan

variables {
bitbucket_datacenter = {
namespace = "my-bitbucket-dc-project"
id = "test-bb-dc-id"
}
}

assert {
condition = spacelift_stack.default["root-module-a-test"].bitbucket_datacenter[0].namespace == "my-bitbucket-dc-project"
error_message = "Bitbucket Data Center namespace was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter)}"
}

assert {
condition = spacelift_stack.default["root-module-a-test"].bitbucket_datacenter[0].id == "test-bb-dc-id"
error_message = "Bitbucket Data Center id was not set correctly: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter)}"
}
}

# Test that VCS blocks are empty when variables are null
run "test_vcs_blocks_empty_when_null" {
command = plan

variables {
github_enterprise = null
raw_git = null
gitlab = null
bitbucket_cloud = null
bitbucket_datacenter = null
}

assert {
condition = length(spacelift_stack.default["root-module-a-test"].github_enterprise) == 0
error_message = "GitHub Enterprise block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].github_enterprise)}"
}

assert {
condition = length(spacelift_stack.default["root-module-a-test"].raw_git) == 0
error_message = "Raw Git block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].raw_git)}"
}

assert {
condition = length(spacelift_stack.default["root-module-a-test"].gitlab) == 0
error_message = "GitLab block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].gitlab)}"
}

assert {
condition = length(spacelift_stack.default["root-module-a-test"].bitbucket_cloud) == 0
error_message = "Bitbucket Cloud block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_cloud)}"
}

assert {
condition = length(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter) == 0
error_message = "Bitbucket Data Center block should be empty when variable is null: ${jsonencode(spacelift_stack.default["root-module-a-test"].bitbucket_datacenter)}"
}
}
27 changes: 27 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@ variable "raw_git" {
default = null
}

variable "gitlab" {
type = object({
namespace = string
id = optional(string)
})
description = "The GitLab integration settings"
default = null
}

variable "bitbucket_cloud" {
type = object({
namespace = string
id = optional(string)
})
description = "The Bitbucket Cloud integration settings"
default = null
}

variable "bitbucket_datacenter" {
type = object({
namespace = string
id = optional(string)
})
description = "The Bitbucket Data Center integration settings"
default = null
}


variable "repository" {
type = string
Expand Down