diff --git a/terraform/aws/codepipeline/README.md b/terraform/aws/codepipeline/README.md
index 2946473..b39751d 100644
--- a/terraform/aws/codepipeline/README.md
+++ b/terraform/aws/codepipeline/README.md
@@ -155,17 +155,35 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [app](#input\_app) | Application name used for resource naming and SSM parameter paths. | `string` | n/a | yes |
-| [codebuild\_project\_arn](#input\_codebuild\_project\_arn) | ARN of the CodeBuild project. Used for IAM permissions. | `string` | n/a | yes |
-| [codebuild\_project\_name](#input\_codebuild\_project\_name) | Name of the CodeBuild project to use in the Build stage. | `string` | n/a | yes |
+| [artifact\_bucket\_name](#input\_artifact\_bucket\_name) | Name of existing S3 bucket for artifacts. Required when create\_artifact\_bucket is false. | `string` | `null` | no |
+| [build\_output\_artifact\_name](#input\_build\_output\_artifact\_name) | Name of the build output artifact. | `string` | `"BuildArtifact"` | no |
+| [codebuild\_project\_arn](#input\_codebuild\_project\_arn) | ARN of the CodeBuild project. Used for IAM permissions. Required when enable\_build\_stage is true. | `string` | `null` | no |
+| [codebuild\_project\_name](#input\_codebuild\_project\_name) | Name of the CodeBuild project to use in the Build stage. Required when enable\_build\_stage is true. | `string` | `null` | no |
+| [codedeploy\_applications](#input\_codedeploy\_applications) | List of CodeDeploy deployment configurations.
Each deployment should have: application\_name, deployment\_group\_name, and optional action\_name, namespace, run\_order. |
list(object({
application_name = string
deployment_group_name = string
action_name = optional(string, null)
namespace = optional(string, null)
run_order = optional(number, null)
})) | `[]` | no |
+| [codestar\_connection\_arn](#input\_codestar\_connection\_arn) | ARN of CodeStar connection for GitHub V2 integration. Required when source\_provider is CodeStarSourceConnection. | `string` | `null` | no |
+| [create\_artifact\_bucket](#input\_create\_artifact\_bucket) | Create a new S3 bucket for artifacts. If false, use existing bucket specified in artifact\_bucket\_name. | `bool` | `true` | no |
+| [create\_service\_role](#input\_create\_service\_role) | Create a new IAM service role for CodePipeline. If false, use existing role specified in service\_role\_arn. | `bool` | `true` | no |
+| [deploy\_action\_namespace](#input\_deploy\_action\_namespace) | Namespace for deploy action variables. | `string` | `"DeployVariables"` | no |
+| [detect\_changes](#input\_detect\_changes) | Whether to detect changes in the source repository for CodeStarSourceConnection. | `bool` | `false` | no |
+| [enable\_build\_stage](#input\_enable\_build\_stage) | Enable Build stage with CodeBuild. If false, pipeline goes directly from Source to Deploy. | `bool` | `false` | no |
+| [enable\_deploy\_stage](#input\_enable\_deploy\_stage) | Enable Deploy stage with CodeDeploy. | `bool` | `true` | no |
| [env](#input\_env) | Environment name used for resource naming and SSM parameter paths. | `string` | n/a | yes |
+| [execution\_mode](#input\_execution\_mode) | Execution mode for V2 pipelines. Valid values: QUEUED, SUPERSEDED, PARALLEL | `string` | `"SUPERSEDED"` | no |
| [github\_branch](#input\_github\_branch) | GitHub branch to monitor for changes and trigger pipeline executions. | `string` | `"main"` | no |
+| [github\_full\_repository\_id](#input\_github\_full\_repository\_id) | Full repository ID in format 'owner/repo' for CodeStarSourceConnection. | `string` | `null` | no |
| [github\_owner](#input\_github\_owner) | GitHub repository owner (organization or username). | `string` | n/a | yes |
| [github\_repo](#input\_github\_repo) | GitHub repository name. | `string` | n/a | yes |
| [kms\_key\_id](#input\_kms\_key\_id) | KMS key ID for S3 bucket encryption.
If not provided, uses AWS-managed encryption (AES256).
For enhanced security, provide a customer-managed KMS key ARN or alias.
Examples:
- Key ARN: arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012
- Alias ARN: arn:aws:kms:us-east-1:123456789012:alias/my-key
- Key ID: 12345678-1234-1234-1234-123456789012 | `string` | `null` | no |
| [mock\_account\_id](#input\_mock\_account\_id) | Mock AWS account ID to use when skip\_data\_source\_lookup is true. | `string` | `"123456789012"` | no |
| [mock\_github\_token](#input\_mock\_github\_token) | Mock GitHub token to use when skip\_data\_source\_lookup is true. | `string` | `"mock-token"` | no |
+| [output\_artifact\_format](#input\_output\_artifact\_format) | Output artifact format for CodeStarSourceConnection. Valid values: CODE\_ZIP, CODEBUILD\_CLONE\_REF | `string` | `"CODE_ZIP"` | no |
| [pipeline\_name](#input\_pipeline\_name) | Name of the CodePipeline. Used for resource naming and tagging. | `string` | n/a | yes |
+| [pipeline\_type](#input\_pipeline\_type) | Pipeline type. Valid values: V1, V2 | `string` | `"V2"` | no |
+| [service\_role\_arn](#input\_service\_role\_arn) | ARN of existing IAM role for CodePipeline. Required when create\_service\_role is false. | `string` | `null` | no |
| [skip\_data\_source\_lookup](#input\_skip\_data\_source\_lookup) | Skip AWS data source lookups for testing without credentials. Uses mock values instead. | `bool` | `false` | no |
+| [source\_action\_namespace](#input\_source\_action\_namespace) | Namespace for source action variables. | `string` | `"SourceVariables"` | no |
+| [source\_output\_artifact\_name](#input\_source\_output\_artifact\_name) | Name of the source output artifact. | `string` | `"SourceArtifact"` | no |
+| [source\_provider](#input\_source\_provider) | Source provider type. Valid values: CodeStarSourceConnection, GitHub | `string` | `"CodeStarSourceConnection"` | no |
| [tags](#input\_tags) | A map of tags to add to all resources. | `map(string)` | `{}` | no |
## Outputs
diff --git a/terraform/aws/codepipeline/main.tf b/terraform/aws/codepipeline/main.tf
index 73fc656..fab05b9 100644
--- a/terraform/aws/codepipeline/main.tf
+++ b/terraform/aws/codepipeline/main.tf
@@ -21,14 +21,17 @@ data "aws_region" "current" {
}
data "aws_ssm_parameter" "github_token" {
- count = var.skip_data_source_lookup ? 0 : 1
+ count = var.skip_data_source_lookup || var.source_provider != "GitHub" ? 0 : 1
name = "/${var.env}/${var.app}/github-token"
}
locals {
- account_id = var.skip_data_source_lookup ? var.mock_account_id : data.aws_caller_identity.current[0].account_id
- region = var.skip_data_source_lookup ? "us-east-1" : data.aws_region.current[0].name
- github_token = var.skip_data_source_lookup ? var.mock_github_token : data.aws_ssm_parameter.github_token[0].value
+ account_id = var.skip_data_source_lookup ? var.mock_account_id : data.aws_caller_identity.current[0].account_id
+ region = var.skip_data_source_lookup ? "us-east-1" : data.aws_region.current[0].name
+ github_token = var.skip_data_source_lookup ? var.mock_github_token : (var.source_provider == "GitHub" ? data.aws_ssm_parameter.github_token[0].value : null)
+ github_full_repo_id = var.github_full_repository_id != null ? var.github_full_repository_id : "${var.github_owner}/${var.github_repo}"
+ artifact_bucket = var.create_artifact_bucket ? aws_s3_bucket.pipeline_artifacts[0].bucket : var.artifact_bucket_name
+ pipeline_role_arn = var.create_service_role ? aws_iam_role.pipeline[0].arn : var.service_role_arn
}
# -----------------------------------------------------------------------------
@@ -36,13 +39,17 @@ locals {
# -----------------------------------------------------------------------------
resource "aws_s3_bucket" "pipeline_artifacts" {
+ count = var.create_artifact_bucket ? 1 : 0
+
bucket = "${var.env}-${var.app}-artifacts-${local.account_id}"
tags = var.tags
}
resource "aws_s3_bucket_versioning" "pipeline_artifacts" {
- bucket = aws_s3_bucket.pipeline_artifacts.id
+ count = var.create_artifact_bucket ? 1 : 0
+
+ bucket = aws_s3_bucket.pipeline_artifacts[0].id
versioning_configuration {
status = "Enabled"
@@ -50,7 +57,9 @@ resource "aws_s3_bucket_versioning" "pipeline_artifacts" {
}
resource "aws_s3_bucket_server_side_encryption_configuration" "pipeline_artifacts" {
- bucket = aws_s3_bucket.pipeline_artifacts.id
+ count = var.create_artifact_bucket ? 1 : 0
+
+ bucket = aws_s3_bucket.pipeline_artifacts[0].id
rule {
apply_server_side_encryption_by_default {
@@ -61,7 +70,9 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "pipeline_artifact
}
resource "aws_s3_bucket_public_access_block" "pipeline_artifacts" {
- bucket = aws_s3_bucket.pipeline_artifacts.id
+ count = var.create_artifact_bucket ? 1 : 0
+
+ bucket = aws_s3_bucket.pipeline_artifacts[0].id
block_public_acls = true
block_public_policy = true
@@ -74,6 +85,8 @@ resource "aws_s3_bucket_public_access_block" "pipeline_artifacts" {
# -----------------------------------------------------------------------------
resource "aws_iam_role" "pipeline" {
+ count = var.create_service_role ? 1 : 0
+
name = "${var.pipeline_name}-role"
assume_role_policy = jsonencode({
@@ -91,8 +104,10 @@ resource "aws_iam_role" "pipeline" {
}
resource "aws_iam_role_policy" "pipeline" {
+ count = var.create_service_role ? 1 : 0
+
name = "${var.pipeline_name}-policy"
- role = aws_iam_role.pipeline.id
+ role = aws_iam_role.pipeline[0].id
policy = jsonencode({
Version = "2012-10-17"
@@ -105,15 +120,34 @@ resource "aws_iam_role_policy" "pipeline" {
"s3:GetObjectVersion",
"s3:PutObject"
]
- Resource = "${aws_s3_bucket.pipeline_artifacts.arn}/*"
+ Resource = "arn:aws:s3:::${local.artifact_bucket}/*"
},
{
Effect = "Allow"
Action = [
"s3:ListBucket"
]
- Resource = aws_s3_bucket.pipeline_artifacts.arn
+ Resource = "arn:aws:s3:::${local.artifact_bucket}"
},
+ {
+ Effect = "Allow"
+ Action = [
+ "ssm:GetParameter",
+ "ssm:GetParameters"
+ ]
+ Resource = "arn:aws:ssm:${local.region}:${local.account_id}:parameter/${var.env}/*"
+ }
+ ],
+ var.source_provider == "CodeStarSourceConnection" && var.codestar_connection_arn != null ? [
+ {
+ Effect = "Allow"
+ Action = [
+ "codestar-connections:UseConnection"
+ ]
+ Resource = var.codestar_connection_arn
+ }
+ ] : [],
+ var.enable_build_stage && var.codebuild_project_arn != null ? [
{
Effect = "Allow"
Action = [
@@ -121,16 +155,22 @@ resource "aws_iam_role_policy" "pipeline" {
"codebuild:StartBuild"
]
Resource = var.codebuild_project_arn
- },
+ }
+ ] : [],
+ var.enable_deploy_stage && length(var.codedeploy_applications) > 0 ? [
{
Effect = "Allow"
Action = [
- "ssm:GetParameter",
- "ssm:GetParameters"
+ "codedeploy:CreateDeployment",
+ "codedeploy:GetApplication",
+ "codedeploy:GetApplicationRevision",
+ "codedeploy:GetDeployment",
+ "codedeploy:GetDeploymentConfig",
+ "codedeploy:RegisterApplicationRevision"
]
- Resource = "arn:aws:ssm:${local.region}:${local.account_id}:parameter/${var.env}/*"
+ Resource = "*"
}
- ],
+ ] : [],
var.kms_key_id != null ? [
{
Effect = "Allow"
@@ -152,26 +192,36 @@ resource "aws_iam_role_policy" "pipeline" {
# -----------------------------------------------------------------------------
resource "aws_codepipeline" "this" {
- name = var.pipeline_name
- role_arn = aws_iam_role.pipeline.arn
+ name = var.pipeline_name
+ role_arn = local.pipeline_role_arn
+ pipeline_type = var.pipeline_type
+ execution_mode = var.pipeline_type == "V2" ? var.execution_mode : null
artifact_store {
- location = aws_s3_bucket.pipeline_artifacts.bucket
+ location = local.artifact_bucket
type = "S3"
}
+ # Source Stage
stage {
name = "Source"
action {
name = "Source"
category = "Source"
- owner = "ThirdParty"
- provider = "GitHub"
+ owner = var.source_provider == "CodeStarSourceConnection" ? "AWS" : "ThirdParty"
+ provider = var.source_provider
version = "1"
- output_artifacts = ["source_output"]
+ output_artifacts = [var.source_output_artifact_name]
+ namespace = var.source_action_namespace
- configuration = {
+ configuration = var.source_provider == "CodeStarSourceConnection" ? {
+ ConnectionArn = var.codestar_connection_arn
+ FullRepositoryId = local.github_full_repo_id
+ BranchName = var.github_branch
+ DetectChanges = tostring(var.detect_changes)
+ OutputArtifactFormat = var.output_artifact_format
+ } : {
Owner = var.github_owner
Repo = var.github_repo
Branch = var.github_branch
@@ -180,23 +230,81 @@ resource "aws_codepipeline" "this" {
}
}
- stage {
- name = "Build"
+ # Build Stage (Optional)
+ dynamic "stage" {
+ for_each = var.enable_build_stage ? [1] : []
+ content {
+ name = "Build"
- action {
- name = "Build"
- category = "Build"
- owner = "AWS"
- provider = "CodeBuild"
- version = "1"
- input_artifacts = ["source_output"]
- output_artifacts = ["build_output"]
+ action {
+ name = "Build"
+ category = "Build"
+ owner = "AWS"
+ provider = "CodeBuild"
+ version = "1"
+ input_artifacts = [var.source_output_artifact_name]
+ output_artifacts = [var.build_output_artifact_name]
+
+ configuration = {
+ ProjectName = var.codebuild_project_name
+ }
+ }
+ }
+ }
+
+ # Deploy Stage (Optional)
+ dynamic "stage" {
+ for_each = var.enable_deploy_stage && length(var.codedeploy_applications) > 0 ? [1] : []
+ content {
+ name = "Deploy"
+
+ dynamic "action" {
+ for_each = var.codedeploy_applications
+ content {
+ name = action.value.action_name != null ? action.value.action_name : (length(var.codedeploy_applications) == 1 ? "Deploy" : "Deploy-${action.value.deployment_group_name}")
+ category = "Deploy"
+ owner = "AWS"
+ provider = "CodeDeploy"
+ version = "1"
+ input_artifacts = [var.enable_build_stage ? var.build_output_artifact_name : var.source_output_artifact_name]
+ namespace = action.value.namespace != null ? action.value.namespace : (action.key == 0 ? var.deploy_action_namespace : null)
+ run_order = action.value.run_order != null ? action.value.run_order : (action.key + 1)
- configuration = {
- ProjectName = var.codebuild_project_name
+ configuration = {
+ ApplicationName = action.value.application_name
+ DeploymentGroupName = action.value.deployment_group_name
+ }
+ }
}
}
}
+ lifecycle {
+ precondition {
+ condition = var.create_service_role || var.service_role_arn != null
+ error_message = "service_role_arn must be provided when create_service_role is false."
+ }
+
+ precondition {
+ condition = var.create_artifact_bucket || var.artifact_bucket_name != null
+ error_message = "artifact_bucket_name must be provided when create_artifact_bucket is false."
+ }
+
+ precondition {
+ condition = var.source_provider != "CodeStarSourceConnection" || var.codestar_connection_arn != null
+ error_message = "codestar_connection_arn must be provided when source_provider is CodeStarSourceConnection."
+ }
+
+ precondition {
+ condition = !var.enable_build_stage || (var.codebuild_project_name != null && var.codebuild_project_arn != null)
+ error_message = "codebuild_project_name and codebuild_project_arn must be provided when enable_build_stage is true."
+ }
+
+ precondition {
+ condition = !var.enable_deploy_stage || length(var.codedeploy_applications) > 0
+ error_message = "codedeploy_applications must be provided when enable_deploy_stage is true."
+ }
+ }
+
tags = var.tags
}
diff --git a/terraform/aws/codepipeline/outputs.tf b/terraform/aws/codepipeline/outputs.tf
index 8c48c55..b7f2aaa 100644
--- a/terraform/aws/codepipeline/outputs.tf
+++ b/terraform/aws/codepipeline/outputs.tf
@@ -23,22 +23,22 @@ output "pipeline_arn" {
output "artifact_bucket_name" {
description = "The name of the S3 bucket for pipeline artifacts."
- value = aws_s3_bucket.pipeline_artifacts.id
+ value = local.artifact_bucket
}
output "artifact_bucket_id" {
description = "The ID of the S3 bucket for pipeline artifacts."
- value = aws_s3_bucket.pipeline_artifacts.id
+ value = local.artifact_bucket
}
output "artifact_bucket_arn" {
description = "The ARN of the S3 bucket for pipeline artifacts."
- value = aws_s3_bucket.pipeline_artifacts.arn
+ value = var.create_artifact_bucket ? aws_s3_bucket.pipeline_artifacts[0].arn : "arn:aws:s3:::${var.artifact_bucket_name}"
}
output "artifact_bucket_region" {
description = "The AWS region of the S3 bucket."
- value = aws_s3_bucket.pipeline_artifacts.region
+ value = var.create_artifact_bucket ? aws_s3_bucket.pipeline_artifacts[0].region : local.region
}
# -----------------------------------------------------------------------------
@@ -47,15 +47,15 @@ output "artifact_bucket_region" {
output "pipeline_role_name" {
description = "The name of the CodePipeline IAM role."
- value = aws_iam_role.pipeline.name
+ value = var.create_service_role ? aws_iam_role.pipeline[0].name : null
}
output "pipeline_role_id" {
description = "The ID of the CodePipeline IAM role."
- value = aws_iam_role.pipeline.id
+ value = var.create_service_role ? aws_iam_role.pipeline[0].id : null
}
output "pipeline_role_arn" {
description = "The ARN of the CodePipeline IAM role."
- value = aws_iam_role.pipeline.arn
+ value = local.pipeline_role_arn
}
diff --git a/terraform/aws/codepipeline/tests/basic/main.tf b/terraform/aws/codepipeline/tests/basic/main.tf
index a168335..59526be 100644
--- a/terraform/aws/codepipeline/tests/basic/main.tf
+++ b/terraform/aws/codepipeline/tests/basic/main.tf
@@ -31,15 +31,20 @@ module "test_basic_pipeline" {
env = "dev"
app = "myapp"
- # GitHub configuration
- github_owner = "myorg"
- github_repo = "myrepo"
- github_branch = "main"
+ # Source configuration (GitHub V1)
+ source_provider = "GitHub"
+ github_owner = "myorg"
+ github_repo = "myrepo"
+ github_branch = "main"
- # CodeBuild integration
+ # Build stage (enabled)
+ enable_build_stage = true
codebuild_project_name = "test-build-project"
codebuild_project_arn = "arn:aws:codebuild:us-east-1:123456789012:project/test-build-project"
+ # Deploy stage (disabled for basic test)
+ enable_deploy_stage = false
+
# Skip real AWS calls for testing
skip_data_source_lookup = true
mock_account_id = "123456789012"
diff --git a/terraform/aws/codepipeline/variables.tf b/terraform/aws/codepipeline/variables.tf
index 65a09f1..8a214a6 100644
--- a/terraform/aws/codepipeline/variables.tf
+++ b/terraform/aws/codepipeline/variables.tf
@@ -17,6 +17,28 @@ variable "pipeline_name" {
}
}
+variable "pipeline_type" {
+ description = "Pipeline type. Valid values: V1, V2"
+ type = string
+ default = "V2"
+
+ validation {
+ condition = contains(["V1", "V2"], var.pipeline_type)
+ error_message = "Pipeline type must be either V1 or V2."
+ }
+}
+
+variable "execution_mode" {
+ description = "Execution mode for V2 pipelines. Valid values: QUEUED, SUPERSEDED, PARALLEL"
+ type = string
+ default = "SUPERSEDED"
+
+ validation {
+ condition = contains(["QUEUED", "SUPERSEDED", "PARALLEL"], var.execution_mode)
+ error_message = "Execution mode must be one of: QUEUED, SUPERSEDED, PARALLEL."
+ }
+}
+
variable "env" {
description = "Environment name used for resource naming and SSM parameter paths."
type = string
@@ -48,9 +70,34 @@ variable "app" {
}
# -----------------------------------------------------------------------------
-# GitHub Configuration
+# Source Configuration
# -----------------------------------------------------------------------------
+variable "source_provider" {
+ description = "Source provider type. Valid values: CodeStarSourceConnection, GitHub"
+ type = string
+ default = "CodeStarSourceConnection"
+
+ validation {
+ condition = contains(["CodeStarSourceConnection", "GitHub"], var.source_provider)
+ error_message = "Source provider must be either CodeStarSourceConnection or GitHub."
+ }
+}
+
+variable "codestar_connection_arn" {
+ description = "ARN of CodeStar connection for GitHub V2 integration. Required when source_provider is CodeStarSourceConnection."
+ type = string
+ default = null
+
+ validation {
+ condition = var.codestar_connection_arn == null || can(regex(
+ "^arn:aws:(codestar-connections|codeconnections):[a-z0-9-]+:[0-9]{12}:connection/[a-f0-9-]+$",
+ var.codestar_connection_arn
+ ))
+ error_message = "CodeStar connection ARN must be a valid ARN format."
+ }
+}
+
variable "github_owner" {
description = "GitHub repository owner (organization or username)."
type = string
@@ -82,25 +129,108 @@ variable "github_branch" {
}
}
+variable "github_full_repository_id" {
+ description = "Full repository ID in format 'owner/repo' for CodeStarSourceConnection."
+ type = string
+ default = null
+}
+
+variable "detect_changes" {
+ description = "Whether to detect changes in the source repository for CodeStarSourceConnection."
+ type = bool
+ default = false
+}
+
+variable "output_artifact_format" {
+ description = "Output artifact format for CodeStarSourceConnection. Valid values: CODE_ZIP, CODEBUILD_CLONE_REF"
+ type = string
+ default = "CODE_ZIP"
+
+ validation {
+ condition = contains(["CODE_ZIP", "CODEBUILD_CLONE_REF"], var.output_artifact_format)
+ error_message = "Output artifact format must be either CODE_ZIP or CODEBUILD_CLONE_REF."
+ }
+}
+
+variable "source_output_artifact_name" {
+ description = "Name of the source output artifact."
+ type = string
+ default = "SourceArtifact"
+}
+
+variable "build_output_artifact_name" {
+ description = "Name of the build output artifact."
+ type = string
+ default = "BuildArtifact"
+}
+
+variable "source_action_namespace" {
+ description = "Namespace for source action variables."
+ type = string
+ default = "SourceVariables"
+}
+
+variable "deploy_action_namespace" {
+ description = "Namespace for deploy action variables."
+ type = string
+ default = "DeployVariables"
+}
+
# -----------------------------------------------------------------------------
-# CodeBuild Integration
+# Build Stage Configuration
# -----------------------------------------------------------------------------
+variable "enable_build_stage" {
+ description = "Enable Build stage with CodeBuild. If false, pipeline goes directly from Source to Deploy."
+ type = bool
+ default = false
+}
+
variable "codebuild_project_name" {
- description = "Name of the CodeBuild project to use in the Build stage."
+ description = "Name of the CodeBuild project to use in the Build stage. Required when enable_build_stage is true."
type = string
+ default = null
}
variable "codebuild_project_arn" {
- description = "ARN of the CodeBuild project. Used for IAM permissions."
+ description = "ARN of the CodeBuild project. Used for IAM permissions. Required when enable_build_stage is true."
type = string
+ default = null
validation {
- condition = can(regex("^arn:aws:codebuild:[a-z0-9-]+:[0-9]{12}:project/[a-zA-Z0-9_-]+$", var.codebuild_project_arn))
+ condition = var.codebuild_project_arn == null || can(regex(
+ "^arn:aws:codebuild:[a-z0-9-]+:[0-9]{12}:project/[a-zA-Z0-9_-]+$",
+ var.codebuild_project_arn
+ ))
error_message = "CodeBuild project ARN must be a valid ARN format."
}
}
+# -----------------------------------------------------------------------------
+# Deploy Stage Configuration
+# -----------------------------------------------------------------------------
+
+variable "enable_deploy_stage" {
+ description = "Enable Deploy stage with CodeDeploy."
+ type = bool
+ default = true
+}
+
+variable "codedeploy_applications" {
+ description = <<-EOT
+ List of CodeDeploy deployment configurations.
+ Each deployment should have: application_name, deployment_group_name, and optional action_name, namespace, run_order.
+ EOT
+ type = list(object({
+ application_name = string
+ deployment_group_name = string
+ action_name = optional(string, null)
+ namespace = optional(string, null)
+ run_order = optional(number, null)
+ }))
+ default = []
+}
+
# -----------------------------------------------------------------------------
# Testing Configuration
# -----------------------------------------------------------------------------
@@ -124,6 +254,43 @@ variable "mock_github_token" {
sensitive = true
}
+# -----------------------------------------------------------------------------
+# Artifact Store Configuration
+# -----------------------------------------------------------------------------
+
+variable "create_artifact_bucket" {
+ description = "Create a new S3 bucket for artifacts. If false, use existing bucket specified in artifact_bucket_name."
+ type = bool
+ default = true
+}
+
+variable "artifact_bucket_name" {
+ description = "Name of existing S3 bucket for artifacts. Required when create_artifact_bucket is false."
+ type = string
+ default = null
+}
+
+# -----------------------------------------------------------------------------
+# Service Role Configuration
+# -----------------------------------------------------------------------------
+
+variable "create_service_role" {
+ description = "Create a new IAM service role for CodePipeline. If false, use existing role specified in service_role_arn."
+ type = bool
+ default = true
+}
+
+variable "service_role_arn" {
+ description = "ARN of existing IAM role for CodePipeline. Required when create_service_role is false."
+ type = string
+ default = null
+
+ validation {
+ condition = var.service_role_arn == null || can(regex("^arn:aws:iam::[0-9]{12}:role/.+$", var.service_role_arn))
+ error_message = "Service role ARN must be a valid IAM role ARN."
+ }
+}
+
# -----------------------------------------------------------------------------
# Security Configuration
# -----------------------------------------------------------------------------