Skip to content

Commit f3b0da4

Browse files
feat: enable integration with ADO (#93)
## what - `azure_devops`. Per the spacelift provider [docs](https://search.opentofu.org/provider/spacelift-io/spacelift/latest/docs/resources/stack#user-content-nestedblock--azure_devops), allow users to integration with ADO. - `raw_git`. Also setup the raw_git VCS setup. - Update the dynamic `github_enterprise` logic allowing `id` to be null in accordance with it's variable declaration ## why ## references https://search.opentofu.org/provider/spacelift-io/spacelift/latest/docs/resources/stack#user-content-nestedblock--azure_devops <img width="1668" height="708" alt="CleanShot 2025-09-13 at 16 09 47@2x" src="https://github.com/user-attachments/assets/08180e3d-4730-4686-b27c-858cc2825451" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added optional Azure DevOps integration for stacks via a new input, enabling configuration with project and integration ID. - Documentation - Updated module documentation to include the Azure DevOps input and its parameters. - Added a complete Azure DevOps usage example with step-by-step setup instructions and links to relevant docs. - Chores - Specified minimum Terraform and Spacelift provider versions for the example to ensure compatibility. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 7597e4d commit f3b0da4

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ If you have many remote repositories that you need to manage via this pattern, y
347347
| <a name="input_aws_integration_attachment_write"></a> [aws\_integration\_attachment\_write](#input\_aws\_integration\_attachment\_write) | Indicates whether this attachment is used for write operations. | `bool` | `true` | no |
348348
| <a name="input_aws_integration_enabled"></a> [aws\_integration\_enabled](#input\_aws\_integration\_enabled) | Indicates whether the AWS integration is enabled. | `bool` | `false` | no |
349349
| <a name="input_aws_integration_id"></a> [aws\_integration\_id](#input\_aws\_integration\_id) | ID of the AWS integration to attach. | `string` | `null` | no |
350+
| <a name="input_azure_devops"></a> [azure\_devops](#input\_azure\_devops) | The Azure DevOps integration settings | <pre>object({<br/> project = string<br/> id = optional(string)<br/> })</pre> | `null` | no |
350351
| <a name="input_before_apply"></a> [before\_apply](#input\_before\_apply) | List of before-apply scripts | `list(string)` | `[]` | no |
351352
| <a name="input_before_destroy"></a> [before\_destroy](#input\_before\_destroy) | List of before-destroy scripts | `list(string)` | `[]` | no |
352353
| <a name="input_before_init"></a> [before\_init](#input\_before\_init) | List of before-init scripts | `list(string)` | `[]` | no |
@@ -371,6 +372,7 @@ If you have many remote repositories that you need to manage via this pattern, y
371372
| <a name="input_labels"></a> [labels](#input\_labels) | List of labels to apply to the stacks. | `list(string)` | `[]` | no |
372373
| <a name="input_manage_state"></a> [manage\_state](#input\_manage\_state) | Determines if Spacelift should manage state for this stack. | `bool` | `false` | no |
373374
| <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 |
375+
| <a name="input_raw_git"></a> [raw\_git](#input\_raw\_git) | The raw Git integration settings | <pre>object({<br/> namespace = string<br/> url = string<br/> })</pre> | `null` | no |
374376
| <a name="input_repository"></a> [repository](#input\_repository) | The name of your infrastructure repo | `string` | n/a | yes |
375377
| <a name="input_root_module_structure"></a> [root\_module\_structure](#input\_root\_module\_structure) | The root module structure of the Stacks that you're reading in. See README for full details.<br/><br/>MultiInstance - You're using Workspaces or Dynamic Backend configuration to create multiple instances of the same root module code.<br/>SingleInstance - You're using copies of a root module and your directory structure to create multiple instances of the same Terraform code. | `string` | `"MultiInstance"` | no |
376378
| <a name="input_root_modules_path"></a> [root\_modules\_path](#input\_root\_modules\_path) | The path, relative to the root of the repository, where the root module can be found. | `string` | `"root-modules"` | no |

examples/azure-devops/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Azure DevOps Integration Example
2+
3+
This example demonstrates how to configure the spacelift-automation module with Azure DevOps as the version control system.
4+
5+
See Spacelift's full walk through here, https://docs.spacelift.io/integrations/source-control/azure-devops
6+
7+
## Configuration
8+
9+
The key difference from GitHub integration is using the `azure_devops` block instead of `github_enterprise`:
10+
11+
```hcl
12+
azure_devops = {
13+
project = "MyProject" # Your Azure DevOps project name
14+
id = "integration-id" # Spacelift Azure DevOps integration ID
15+
}
16+
```
17+
18+
## Usage
19+
20+
1. Update the `azure_devops.project` and `azure_devops.id` values with your Azure DevOps project and Spacelift integration ID
21+
2. Update the `repository` value with your actual repository name
22+
3. Run `terraform init` and `terraform plan` to see what resources will be created

examples/azure-devops/main.tf

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module "automation_azure_devops" {
2+
source = "../../"
3+
4+
azure_devops = {
5+
project = "MyProject-Spacelift-Project"
6+
id = "name-of-your-azure-devops-integration-in-spacelift"
7+
}
8+
repository = "MyProject-Spacelift-Project"
9+
branch = "main"
10+
11+
root_modules_path = "../../examples/complete/root-modules"
12+
all_root_modules_enabled = true
13+
14+
aws_integration_id = "01JEC7ZACVKHTSVY4NF8QNZVVB"
15+
aws_integration_enabled = true
16+
}
17+
18+
module "spacelift_policies" {
19+
source = "masterpointio/spacelift/policies"
20+
version = "0.2.0"
21+
22+
policies = {
23+
"access-default" = {
24+
body = <<-EOT
25+
package spacelift
26+
default allow = true
27+
EOT
28+
type = "ACCESS"
29+
description = "Policy allowing access to resources"
30+
labels = ["team:sre", "env:dev"]
31+
}
32+
33+
"trigger-administrative" = {
34+
body_url = "https://raw.githubusercontent.com/cloudposse/terraform-spacelift-cloud-infrastructure-automation/1.6.0/catalog/policies/trigger.administrative.rego"
35+
type = "TRIGGER"
36+
labels = ["autoattach:*"] # Showcasing how to attach to ALL stacks
37+
}
38+
}
39+
}

examples/azure-devops/versions.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.9"
3+
4+
required_providers {
5+
spacelift = {
6+
source = "spacelift-io/spacelift"
7+
version = ">= 1.14"
8+
}
9+
}
10+
}

main.tf

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ locals {
369369
for stack in local.stacks : stack => try(coalesce(
370370
try(local.stack_configs[stack].worker_pool_id, null), # worker_pool_id always takes precedence since it's the most explicit
371371
try(local.worker_pool_name_to_id[local.stack_configs[stack].worker_pool_name], null), # Then try to look up worker_pool_name from the stack.yaml to ID
372-
var.worker_pool_id, # Then try to use the global variable worker_pool_id
372+
var.worker_pool_id, # Then try to use the global variable worker_pool_id
373373
try(local.worker_pool_name_to_id[var.worker_pool_name], null), # Then try to look up the global variable worker_pool_name to ID
374374
), null) # If no worker_pool_id or worker_pool_name is provided, default to null
375375
}
@@ -465,7 +465,23 @@ resource "spacelift_stack" "default" {
465465
for_each = var.github_enterprise != null ? [var.github_enterprise] : []
466466
content {
467467
namespace = github_enterprise.value["namespace"]
468-
id = github_enterprise.value["id"]
468+
id = try(github_enterprise.value["id"], null)
469+
}
470+
}
471+
472+
dynamic "azure_devops" {
473+
for_each = var.azure_devops != null ? [var.azure_devops] : []
474+
content {
475+
project = azure_devops.value["project"]
476+
id = try(azure_devops.value["id"], null)
477+
}
478+
}
479+
480+
dynamic "raw_git" {
481+
for_each = var.raw_git != null ? [var.raw_git] : []
482+
content {
483+
namespace = raw_git.value["namespace"]
484+
url = raw_git.value["url"]
469485
}
470486
}
471487
}

variables.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ variable "github_enterprise" {
3636
default = null
3737
}
3838

39+
variable "azure_devops" {
40+
type = object({
41+
project = string
42+
id = optional(string)
43+
})
44+
description = "The Azure DevOps integration settings"
45+
default = null
46+
}
47+
48+
variable "raw_git" {
49+
type = object({
50+
namespace = string
51+
url = string
52+
})
53+
description = "The raw Git integration settings"
54+
default = null
55+
}
56+
57+
3958
variable "repository" {
4059
type = string
4160
description = "The name of your infrastructure repo"

0 commit comments

Comments
 (0)