From 9c47ef5d5b1daa497c4eeaecf5180e1120594dd1 Mon Sep 17 00:00:00 2001 From: akocbek Date: Thu, 16 Oct 2025 13:38:09 +0100 Subject: [PATCH 1/9] feat: add support to create container registry and secret inside build module --- examples/build/README.md | 8 +++++ examples/build/main.tf | 30 +++++++++++++++++++ examples/build/outputs.tf | 24 +++++++++++++++ examples/build/provider.tf | 8 +++++ examples/build/variables.tf | 27 +++++++++++++++++ examples/build/version.tf | 12 ++++++++ main.tf | 39 +++++++++++++----------- modules/build/README.md | 19 ++++++++---- modules/build/main.tf | 51 ++++++++++++++++++++++++++++++-- modules/build/variables.tf | 59 ++++++++++++++++++++++++++++++++----- variables.tf | 25 +++++++++------- 11 files changed, 258 insertions(+), 44 deletions(-) create mode 100644 examples/build/README.md create mode 100644 examples/build/main.tf create mode 100644 examples/build/outputs.tf create mode 100644 examples/build/provider.tf create mode 100644 examples/build/variables.tf create mode 100644 examples/build/version.tf diff --git a/examples/build/README.md b/examples/build/README.md new file mode 100644 index 00000000..6064020c --- /dev/null +++ b/examples/build/README.md @@ -0,0 +1,8 @@ +# Build example + +An end-to-end apps example that will provision the following: +- A new resource group if one is not passed in. +- Code Engine project +- Code Engine build +- Code Engine registry secret +- Container registry namespace diff --git a/examples/build/main.tf b/examples/build/main.tf new file mode 100644 index 00000000..1e4666e3 --- /dev/null +++ b/examples/build/main.tf @@ -0,0 +1,30 @@ +######################################################################################################################## +# Resource group +######################################################################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.3.0" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +######################################################################################################################## +# Code Engine instance +######################################################################################################################## + +module "code_engine" { + source = "../.." + ibmcloud_api_key = var.ibmcloud_api_key + resource_group_id = module.resource_group.resource_group_id + project_name = "${var.prefix}-project" + builds = { + "${var.prefix}-build1" = { + source_url = "https://github.com/IBM/CodeEngine" + container_registry_namespace = "cr-ce" + prefix = var.prefix + region = var.region + } + } +} diff --git a/examples/build/outputs.tf b/examples/build/outputs.tf new file mode 100644 index 00000000..7fad9d03 --- /dev/null +++ b/examples/build/outputs.tf @@ -0,0 +1,24 @@ +######################################################################################################################## +# Outputs +######################################################################################################################## + +output "resource_group_id" { + description = "The id of created resource group." + value = module.resource_group.resource_group_id +} + +output "resource_group_name" { + description = "The name of created resource group." + value = module.resource_group.resource_group_name +} + +output "project_id" { + description = "ID of the created code engine project." + value = module.code_engine.project_id +} + +output "build" { + description = "Configuration of the created code engine domain mapping." + value = module.code_engine.build + sensitive = true +} diff --git a/examples/build/provider.tf b/examples/build/provider.tf new file mode 100644 index 00000000..84b69850 --- /dev/null +++ b/examples/build/provider.tf @@ -0,0 +1,8 @@ +######################################################################################################################## +# Provider config +######################################################################################################################## + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/examples/build/variables.tf b/examples/build/variables.tf new file mode 100644 index 00000000..7fbea71e --- /dev/null +++ b/examples/build/variables.tf @@ -0,0 +1,27 @@ +######################################################################################################################## +# Input variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region to provision all resources created by this example" + default = "us-south" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources created by this example" + default = "ce-build" +} + +variable "resource_group" { + type = string + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + default = null +} diff --git a/examples/build/version.tf b/examples/build/version.tf new file mode 100644 index 00000000..59c11feb --- /dev/null +++ b/examples/build/version.tf @@ -0,0 +1,12 @@ + +terraform { + required_version = ">= 1.9.0" + # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (this example), and 1 example that will always use the latest provider version (jobs examples). + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.79.0, < 2.0.0" + } + } +} diff --git a/main.tf b/main.tf index 226ed328..f5b783ac 100644 --- a/main.tf +++ b/main.tf @@ -99,24 +99,27 @@ module "secret" { # Code Engine Build ############################################################################## module "build" { - depends_on = [module.secret] - source = "./modules/build" - for_each = var.builds - ibmcloud_api_key = var.ibmcloud_api_key - existing_resource_group_id = var.resource_group_id - project_id = local.project_id - name = each.key - output_image = each.value.output_image - output_secret = each.value.output_secret - source_url = each.value.source_url - strategy_type = each.value.strategy_type - source_context_dir = each.value.source_context_dir - source_revision = each.value.source_revision - source_secret = each.value.source_secret - source_type = each.value.source_type - strategy_size = each.value.strategy_size - strategy_spec_file = each.value.strategy_spec_file - timeout = each.value.timeout + depends_on = [module.secret] + source = "./modules/build" + for_each = var.builds + ibmcloud_api_key = var.ibmcloud_api_key + existing_resource_group_id = var.resource_group_id + project_id = local.project_id + name = each.key + output_image = each.value.output_image + output_secret = each.value.output_secret + source_url = each.value.source_url + strategy_type = each.value.strategy_type + source_context_dir = each.value.source_context_dir + source_revision = each.value.source_revision + source_secret = each.value.source_secret + source_type = each.value.source_type + strategy_size = each.value.strategy_size + strategy_spec_file = each.value.strategy_spec_file + timeout = each.value.timeout + region = each.value.region + container_registry_namespace = each.value.container_registry_namespace + prefix = each.value.prefix } ############################################################################## diff --git a/modules/build/README.md b/modules/build/README.md index cd4ef77e..a8ccd25d 100644 --- a/modules/build/README.md +++ b/modules/build/README.md @@ -40,7 +40,11 @@ You need the following permissions to run this module. ### Modules -No modules. +| Name | Source | Version | +|------|--------|---------| +| [cr\_endpoint](#module\_cr\_endpoint) | terraform-ibm-modules/container-registry/ibm//modules/endpoint | 2.1.0 | +| [cr\_namespace](#module\_cr\_namespace) | terraform-ibm-modules/container-registry/ibm | 2.1.0 | +| [secret](#module\_secret) | ../../modules/secret | n/a | ### Resources @@ -54,21 +58,24 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [container\_registry\_api\_key](#input\_container\_registry\_api\_key) | The API key for the container registry in the target account. This is only used if 'output\_secret' is not set and a new registry secret needs to be created. If not provided, the IBM Cloud API key (ibmcloud\_api\_key) will be used instead. | `string` | `null` | no | +| [container\_registry\_namespace](#input\_container\_registry\_namespace) | The name of the namespace to create in IBM Cloud Container Registry for organizing container images. Must be set if 'output\_image' is not set. | `string` | `null` | no | | [existing\_resource\_group\_id](#input\_existing\_resource\_group\_id) | The ID of an existing resource group where build will be provisioned. This must be the same resource group in which the code engine project was created. | `string` | n/a | yes | | [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key. | `string` | n/a | yes | | [name](#input\_name) | The name of the build. | `string` | n/a | yes | -| [output\_image](#input\_output\_image) | The name of the image. | `string` | n/a | yes | -| [output\_secret](#input\_output\_secret) | The secret that is required to access the image registry. | `string` | n/a | yes | +| [output\_image](#input\_output\_image) | A container image can be identified by a container image reference with the following structure: registry / namespace / repository:tag. [Learn more](https://cloud.ibm.com/docs/codeengine?topic=codeengine-getting-started).

If not provided, the value will be derived from the 'container\_registry\_namespace' input variable, which must not be null in that case. | `string` | `null` | no | +| [output\_secret](#input\_output\_secret) | The secret that is required to access the IBM Cloud Container Registry. Make sure that the secret is granted with push permissions towards the specified container registry namespace. If not provided, it will be created using the value of 'container\_registry\_api\_key'; if that is not set, 'ibmcloud\_api\_key' will be used instead. | `string` | `null` | no | +| [prefix](#input\_prefix) | Prefix appended to the container registry namespace and registry secret if created. | `string` | `null` | no | | [project\_id](#input\_project\_id) | The ID of the project where build will be created. | `string` | n/a | yes | | [region](#input\_region) | The region in which to provision the build. This must be the same region in which the code engine project was created. | `string` | `"us-south"` | no | | [source\_context\_dir](#input\_source\_context\_dir) | The directory in the repository that contains the buildpacks file or the Dockerfile. | `string` | `null` | no | | [source\_revision](#input\_source\_revision) | Commit, tag, or branch in the source repository to pull. | `string` | `null` | no | -| [source\_secret](#input\_source\_secret) | The name of the secret that is used access the repository source. If the var.source\_type value is `local`, this field must be omitted. | `string` | `null` | no | -| [source\_type](#input\_source\_type) | Specifies the type of source to determine if your build source is in a repository or based on local source code. | `string` | `null` | no | +| [source\_secret](#input\_source\_secret) | The name of the secret that is used access the repository source. If the var.source\_type value is `local`, this input must be omitted. | `string` | `null` | no | +| [source\_type](#input\_source\_type) | Specifies the type of source to determine if your build source is in a repository or based on local source code. If the value is `local`, then 'source\_secret' input must be omitted. | `string` | `null` | no | | [source\_url](#input\_source\_url) | The URL of the code repository. | `string` | n/a | yes | | [strategy\_size](#input\_strategy\_size) | The size for the build, which determines the amount of resources used. | `string` | `null` | no | | [strategy\_spec\_file](#input\_strategy\_spec\_file) | The path to the specification file that is used for build strategies for building an image. | `string` | `null` | no | -| [strategy\_type](#input\_strategy\_type) | The strategy to use for building the image. | `string` | n/a | yes | +| [strategy\_type](#input\_strategy\_type) | The strategy to use for building the image. | `string` | `"dockerfile"` | no | | [timeout](#input\_timeout) | The maximum amount of time, in seconds, that can pass before the build must succeed or fail. | `number` | `600` | no | ### Outputs diff --git a/modules/build/main.tf b/modules/build/main.tf index 0efb886a..814042b7 100644 --- a/modules/build/main.tf +++ b/modules/build/main.tf @@ -4,11 +4,15 @@ # Create Code Engine build ############################################################################## +locals { + prefix = var.prefix != null ? (trimspace(var.prefix) != "" ? "${var.prefix}-" : "") : "" +} + resource "ibm_code_engine_build" "ce_build" { project_id = var.project_id name = var.name - output_image = var.output_image - output_secret = var.output_secret + output_image = local.output_image + output_secret = var.output_secret != null ? var.output_secret : module.secret[0].name source_url = var.source_url source_context_dir = var.source_context_dir source_revision = var.source_revision @@ -39,3 +43,46 @@ resource "terraform_data" "run_build" { } } } + + +############################################################################## +# Container Registry +############################################################################## + +locals { + create_cr_namespace = var.output_image == null && var.container_registry_namespace != null ? true : false + image_container = local.create_cr_namespace ? "${module.cr_endpoint[0].container_registry_endpoint_private}/${module.cr_namespace[0].namespace_name}" : null + output_image = local.create_cr_namespace ? "${local.image_container}/${var.name}" : var.output_image +} + +module "cr_namespace" { + count = local.create_cr_namespace ? 1 : 0 + source = "terraform-ibm-modules/container-registry/ibm" + version = "2.1.0" + namespace_name = "${local.prefix}${var.container_registry_namespace}" + resource_group_id = var.existing_resource_group_id +} + +module "cr_endpoint" { + count = local.create_cr_namespace ? 1 : 0 + source = "terraform-ibm-modules/container-registry/ibm//modules/endpoint" + version = "2.1.0" + region = var.region +} + +############################################################################## +# Code Engine Secret +############################################################################## + +module "secret" { + count = var.output_secret == null ? 1 : 0 + source = "../../modules/secret" + project_id = var.project_id + name = "${local.prefix}registry-access-secret" + data = { + password = var.container_registry_api_key != null ? var.container_registry_api_key : var.ibmcloud_api_key, + username = "iamapikey", + server = module.cr_endpoint[0].container_registry_endpoint_private + } + format = "registry" +} diff --git a/modules/build/variables.tf b/modules/build/variables.tf index c4828f17..fb58eb5b 100644 --- a/modules/build/variables.tf +++ b/modules/build/variables.tf @@ -8,6 +8,12 @@ variable "ibmcloud_api_key" { sensitive = true } +variable "prefix" { + type = string + description = "Prefix appended to the container registry namespace and registry secret if created." + default = null +} + variable "existing_resource_group_id" { description = "The ID of an existing resource group where build will be provisioned. This must be the same resource group in which the code engine project was created." type = string @@ -24,18 +30,19 @@ variable "name" { } variable "output_image" { - description = "The name of the image." - type = string -} + description = < Date: Mon, 3 Nov 2025 15:43:51 +0000 Subject: [PATCH 2/9] update merge conflicts --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38bee374..66d8c256 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ No resources. |------|-------------|------|---------|:--------:| | [apps](#input\_apps) | A map of code engine apps to be created. |
map(object({
image_reference = string
image_secret = optional(string)
run_env_variables = optional(list(object({
type = optional(string)
name = optional(string)
value = optional(string)
prefix = optional(string)
key = optional(string)
reference = optional(string)
})))
run_volume_mounts = optional(list(object({
mount_path = string
reference = string
name = optional(string)
type = string
})))
image_port = optional(number)
managed_domain_mappings = optional(string)
run_arguments = optional(list(string))
run_as_user = optional(number)
run_commands = optional(list(string))
run_service_account = optional(string)
scale_concurrency = optional(number)
scale_concurrency_target = optional(number)
scale_cpu_limit = optional(string)
scale_ephemeral_storage_limit = optional(string)
scale_initial_instances = optional(number)
scale_max_instances = optional(number)
scale_memory_limit = optional(string)
scale_min_instances = optional(number)
scale_request_timeout = optional(number)
scale_down_delay = optional(number)
}))
| `{}` | no | | [bindings](#input\_bindings) | A map of code engine bindings to be created. |
map(object({
secret_name = string
components = list(object({
name = string
resource_type = string
}))
}))
| `{}` | no | -| [builds](#input\_builds) | A map of code engine builds to be created. Requires 'ibmcloud\_api\_key' to be set for authentication and execution. |
map(object({
output_image = string
output_secret = string # pragma: allowlist secret
source_url = string
strategy_type = string
source_context_dir = optional(string)
source_revision = optional(string)
source_secret = optional(string)
source_type = optional(string)
strategy_size = optional(string)
strategy_spec_file = optional(string)
timeout = optional(number)
}))
| `{}` | no | +| [builds](#input\_builds) | A map of code engine builds to be created. Requires 'ibmcloud\_api\_key' to be set for authentication and execution. |
map(object({
output_image = optional(string)
output_secret = optional(string) # pragma: allowlist secret
source_url = string
strategy_type = optional(string)
source_context_dir = optional(string)
source_revision = optional(string)
source_secret = optional(string)
source_type = optional(string)
strategy_size = optional(string)
strategy_spec_file = optional(string)
timeout = optional(number)
region = optional(string)
container_registry_namespace = optional(string)
prefix = optional(string)
}))
| `{}` | no | | [cbr\_rules](#input\_cbr\_rules) | The context-based restrictions rule to create. Only one rule is allowed. |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | | [config\_maps](#input\_config\_maps) | A map of code engine config maps to be created. |
map(object({
data = map(string)
}))
| `{}` | no | | [domain\_mappings](#input\_domain\_mappings) | A map of code engine domain mappings to be created. |
map(object({
tls_secret = string # pragma: allowlist secret
components = list(object({
name = string
resource_type = string
}))
}))
| `{}` | no | From 6ebfc4d958b7515a975095150be8e01d309070ea Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 09:06:08 +0000 Subject: [PATCH 3/9] address PR comments --- modules/build/main.tf | 8 +++++--- modules/build/variables.tf | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/modules/build/main.tf b/modules/build/main.tf index 814042b7..f6e0807d 100644 --- a/modules/build/main.tf +++ b/modules/build/main.tf @@ -50,8 +50,11 @@ resource "terraform_data" "run_build" { ############################################################################## locals { + # Determine if we need to create the container registry namespace or not create_cr_namespace = var.output_image == null && var.container_registry_namespace != null ? true : false - image_container = local.create_cr_namespace ? "${module.cr_endpoint[0].container_registry_endpoint_private}/${module.cr_namespace[0].namespace_name}" : null + # Determine the container image reference based on whether we create the namespace or not + image_container = local.create_cr_namespace ? "${module.cr_endpoint.container_registry_endpoint_private}/${module.cr_namespace[0].namespace_name}" : null + # Determine the final image reference to use: either the newly created image or the user-provided output_image output_image = local.create_cr_namespace ? "${local.image_container}/${var.name}" : var.output_image } @@ -64,7 +67,6 @@ module "cr_namespace" { } module "cr_endpoint" { - count = local.create_cr_namespace ? 1 : 0 source = "terraform-ibm-modules/container-registry/ibm//modules/endpoint" version = "2.1.0" region = var.region @@ -82,7 +84,7 @@ module "secret" { data = { password = var.container_registry_api_key != null ? var.container_registry_api_key : var.ibmcloud_api_key, username = "iamapikey", - server = module.cr_endpoint[0].container_registry_endpoint_private + server = module.cr_endpoint.container_registry_endpoint_private } format = "registry" } diff --git a/modules/build/variables.tf b/modules/build/variables.tf index fb58eb5b..1538e74c 100644 --- a/modules/build/variables.tf +++ b/modules/build/variables.tf @@ -68,6 +68,16 @@ variable "source_type" { description = "Specifies the type of source to determine if your build source is in a repository or based on local source code. If the value is `local`, then 'source_secret' input must be omitted." type = string default = null + + validation { + condition = contains(["git", "local"], var.source_type) + error_message = "'source_type' can be 'git' or 'local' only" + } + + validation { + condition = var.source_type != "local" || var.source_secret == null + error_message = "If 'source_type' is 'local', 'source_secret' must not be provided." + } } variable "source_url" { @@ -105,7 +115,7 @@ variable "timeout" { ############################################################################## variable "container_registry_namespace" { - description = "The name of the namespace to create in IBM Cloud Container Registry for organizing container images. Must be set if 'output_image' is not set." + description = "The name of the namespace to create in IBM Cloud Container Registry for organizing container images. Must be set if 'output_image' is not set. If a prefix input variable is specified, the prefix is added to the name in the `-` format." type = string default = null @@ -119,7 +129,11 @@ variable "container_registry_namespace" { } variable "output_secret" { - description = "The secret that is required to access the IBM Cloud Container Registry. Make sure that the secret is granted with push permissions towards the specified container registry namespace. If not provided, it will be created using the value of 'container_registry_api_key'; if that is not set, 'ibmcloud_api_key' will be used instead." + description = <-` will be created automatically. Its value will be taken from 'container_registry_api_key' if set, otherwise from 'ibmcloud_api_key'. +EOT type = string default = null From 5fa71d6942cf56f40b42cc594bb81b615ac32224 Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 09:09:46 +0000 Subject: [PATCH 4/9] address PR comments --- modules/build/README.md | 4 ++-- modules/build/main.tf | 4 ++-- modules/build/variables.tf | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/build/README.md b/modules/build/README.md index a8ccd25d..db81bd75 100644 --- a/modules/build/README.md +++ b/modules/build/README.md @@ -59,12 +59,12 @@ You need the following permissions to run this module. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [container\_registry\_api\_key](#input\_container\_registry\_api\_key) | The API key for the container registry in the target account. This is only used if 'output\_secret' is not set and a new registry secret needs to be created. If not provided, the IBM Cloud API key (ibmcloud\_api\_key) will be used instead. | `string` | `null` | no | -| [container\_registry\_namespace](#input\_container\_registry\_namespace) | The name of the namespace to create in IBM Cloud Container Registry for organizing container images. Must be set if 'output\_image' is not set. | `string` | `null` | no | +| [container\_registry\_namespace](#input\_container\_registry\_namespace) | The name of the namespace to create in IBM Cloud Container Registry for organizing container images. Must be set if 'output\_image' is not set. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `null` | no | | [existing\_resource\_group\_id](#input\_existing\_resource\_group\_id) | The ID of an existing resource group where build will be provisioned. This must be the same resource group in which the code engine project was created. | `string` | n/a | yes | | [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key. | `string` | n/a | yes | | [name](#input\_name) | The name of the build. | `string` | n/a | yes | | [output\_image](#input\_output\_image) | A container image can be identified by a container image reference with the following structure: registry / namespace / repository:tag. [Learn more](https://cloud.ibm.com/docs/codeengine?topic=codeengine-getting-started).

If not provided, the value will be derived from the 'container\_registry\_namespace' input variable, which must not be null in that case. | `string` | `null` | no | -| [output\_secret](#input\_output\_secret) | The secret that is required to access the IBM Cloud Container Registry. Make sure that the secret is granted with push permissions towards the specified container registry namespace. If not provided, it will be created using the value of 'container\_registry\_api\_key'; if that is not set, 'ibmcloud\_api\_key' will be used instead. | `string` | `null` | no | +| [output\_secret](#input\_output\_secret) | The name of the Code Engine secret that contains an API key to access the IBM Cloud Container Registry.
The API key stored in this secret must have push permissions for the specified container registry namespace.
If this secret is not provided, a Code Engine secret named `-` will be created automatically. Its value will be taken from 'container\_registry\_api\_key' if set, otherwise from 'ibmcloud\_api\_key'. | `string` | `null` | no | | [prefix](#input\_prefix) | Prefix appended to the container registry namespace and registry secret if created. | `string` | `null` | no | | [project\_id](#input\_project\_id) | The ID of the project where build will be created. | `string` | n/a | yes | | [region](#input\_region) | The region in which to provision the build. This must be the same region in which the code engine project was created. | `string` | `"us-south"` | no | diff --git a/modules/build/main.tf b/modules/build/main.tf index f6e0807d..59cb5338 100644 --- a/modules/build/main.tf +++ b/modules/build/main.tf @@ -53,9 +53,9 @@ locals { # Determine if we need to create the container registry namespace or not create_cr_namespace = var.output_image == null && var.container_registry_namespace != null ? true : false # Determine the container image reference based on whether we create the namespace or not - image_container = local.create_cr_namespace ? "${module.cr_endpoint.container_registry_endpoint_private}/${module.cr_namespace[0].namespace_name}" : null + image_container = local.create_cr_namespace ? "${module.cr_endpoint.container_registry_endpoint_private}/${module.cr_namespace[0].namespace_name}" : null # Determine the final image reference to use: either the newly created image or the user-provided output_image - output_image = local.create_cr_namespace ? "${local.image_container}/${var.name}" : var.output_image + output_image = local.create_cr_namespace ? "${local.image_container}/${var.name}" : var.output_image } module "cr_namespace" { diff --git a/modules/build/variables.tf b/modules/build/variables.tf index 1538e74c..9896758e 100644 --- a/modules/build/variables.tf +++ b/modules/build/variables.tf @@ -70,12 +70,12 @@ variable "source_type" { default = null validation { - condition = contains(["git", "local"], var.source_type) + condition = contains(["git", "local"], var.source_type) error_message = "'source_type' can be 'git' or 'local' only" } validation { - condition = var.source_type != "local" || var.source_secret == null + condition = var.source_type != "local" || var.source_secret == null error_message = "If 'source_type' is 'local', 'source_secret' must not be provided." } } @@ -130,8 +130,8 @@ variable "container_registry_namespace" { variable "output_secret" { description = <-` will be created automatically. Its value will be taken from 'container_registry_api_key' if set, otherwise from 'ibmcloud_api_key'. EOT type = string From b51cd3fb72cae5ceef2965c967b4ada9b4e606c9 Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 11:17:00 +0000 Subject: [PATCH 5/9] remove unused code and add tests --- modules/build/variables.tf | 2 +- tests/pr_test.go | 60 ++++++++++++++++++++++++++++++++++-- tests/resources/README.md | 1 - tests/resources/main.tf | 31 ------------------- tests/resources/outputs.tf | 19 ------------ tests/resources/provider.tf | 8 ----- tests/resources/variables.tf | 43 -------------------------- tests/resources/version.tf | 12 -------- 8 files changed, 59 insertions(+), 117 deletions(-) delete mode 100644 tests/resources/README.md delete mode 100644 tests/resources/main.tf delete mode 100644 tests/resources/outputs.tf delete mode 100644 tests/resources/provider.tf delete mode 100644 tests/resources/variables.tf delete mode 100644 tests/resources/version.tf diff --git a/modules/build/variables.tf b/modules/build/variables.tf index 9896758e..d215b290 100644 --- a/modules/build/variables.tf +++ b/modules/build/variables.tf @@ -70,7 +70,7 @@ variable "source_type" { default = null validation { - condition = contains(["git", "local"], var.source_type) + condition = var.source_type == null ? true : contains(["git", "local"], var.source_type) error_message = "'source_type' can be 'git' or 'local' only" } diff --git a/tests/pr_test.go b/tests/pr_test.go index 191c8e2a..0a5143a8 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -16,6 +16,7 @@ import ( const resourceGroup = "geretain-test-resources" const appsExampleDir = "examples/apps" const jobsExampleDir = "examples/jobs" +const buildExampleDir = "examples/build" // Define a struct with fields that match the structure of the YAML data const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" @@ -118,7 +119,7 @@ func TestRunUpgradeAppsExamplesInSchematics(t *testing.T) { } func TestRunJobsExample(t *testing.T) { - + t.Parallel() options := setupJobsExampleOptions(t, "ce-jobs", jobsExampleDir) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") @@ -126,7 +127,7 @@ func TestRunJobsExample(t *testing.T) { } func TestRunJobsUpgradeExample(t *testing.T) { - + t.Parallel() options := setupJobsExampleOptions(t, "ce-jobs-upg", jobsExampleDir) output, err := options.RunTestUpgrade() if !options.UpgradeTestSkipped { @@ -134,3 +135,58 @@ func TestRunJobsUpgradeExample(t *testing.T) { assert.NotNil(t, output, "Expected some output") } } + +func TestRunBuildExampleInSchematics(t *testing.T) { + t.Parallel() + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + TemplateFolder: buildExampleDir, + Prefix: "ce-b-shem", + TarIncludePatterns: []string{ + "*.tf", + buildExampleDir + "/*.tf", + "modules/app/*.tf", + "modules/binding/*.tf", + "modules/config_map/*.tf", + "modules/project/*.tf", + "modules/secret/*.tf", + "modules/build/*.tf", + "modules/build/scripts/build-run.sh", + "modules/domain_mapping/*.tf", + "modules/job/*.tf", + }, + ResourceGroup: resourceGroup, + Tags: []string{"test-schematic"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + }) + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "resource_group", Value: options.ResourceGroup, DataType: "string"}, + {Name: "prefix", Value: options.Prefix + "-b", DataType: "string"}, + {Name: "region", Value: options.Region, DataType: "string"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") +} + +func TestRunBuildExample(t *testing.T) { + t.Parallel() + options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ + Testing: t, + TerraformDir: buildExampleDir, + Prefix: "ce-build", + ResourceGroup: resourceGroup, + }) + options.TerraformVars = map[string]interface{}{ + "resource_group": resourceGroup, + "prefix": options.Prefix, + "ibmcloud_api_key": options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], + } + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} diff --git a/tests/resources/README.md b/tests/resources/README.md deleted file mode 100644 index 4bb3621d..00000000 --- a/tests/resources/README.md +++ /dev/null @@ -1 +0,0 @@ -The terraform code in this directory is used by the existing resource test in tests/pr_test.go diff --git a/tests/resources/main.tf b/tests/resources/main.tf deleted file mode 100644 index c09d5bda..00000000 --- a/tests/resources/main.tf +++ /dev/null @@ -1,31 +0,0 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.4.0" - # if an existing resource group is not set (null) create a new one using prefix - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group -} - -######################################################################################################################## -# Secrets Manager resources -######################################################################################################################## - -data "ibm_sm_public_certificate" "public_certificate" { - # depends_on = [resource.ibm_sm_public_certificate.secrets_manager_public_certificate] - instance_id = var.existing_sm_instance_guid - region = var.existing_sm_instance_region - secret_id = var.existing_cert_secret_id -} - - -module "namespace" { - source = "terraform-ibm-modules/container-registry/ibm" - version = "2.3.5" - namespace_name = "${var.prefix}-namespace" - resource_group_id = module.resource_group.resource_group_id - images_per_repo = 1 -} diff --git a/tests/resources/outputs.tf b/tests/resources/outputs.tf deleted file mode 100644 index 88c0e756..00000000 --- a/tests/resources/outputs.tf +++ /dev/null @@ -1,19 +0,0 @@ -######################################################################################################################## -# Outputs -######################################################################################################################## -output "tls_cert" { - value = format("%s%s", data.ibm_sm_public_certificate.public_certificate.certificate, data.ibm_sm_public_certificate.public_certificate.intermediate) - sensitive = true - description = "The TLS certificate." -} - -output "tls_key" { - value = data.ibm_sm_public_certificate.public_certificate.private_key - sensitive = true - description = "The TLS private key." -} - -output "cr_name" { - value = module.namespace.namespace_name - description = "The name of the container registry namespace." -} diff --git a/tests/resources/provider.tf b/tests/resources/provider.tf deleted file mode 100644 index 292d3202..00000000 --- a/tests/resources/provider.tf +++ /dev/null @@ -1,8 +0,0 @@ -######################################################################################################################## -# Provider config -######################################################################################################################## - -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.existing_sm_instance_region -} diff --git a/tests/resources/variables.tf b/tests/resources/variables.tf deleted file mode 100644 index 5206953f..00000000 --- a/tests/resources/variables.tf +++ /dev/null @@ -1,43 +0,0 @@ -######################################################################################################################## -# Input variables -######################################################################################################################## - -variable "ibmcloud_api_key" { - type = string - description = "The IBM Cloud API Key" - sensitive = true -} - -variable "prefix" { - type = string - description = "Prefix to append to all resources created by this example" - default = "ce-prj" -} - -variable "resource_group" { - type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" - default = null -} - -############################################################## -# Secret Manager -############################################################## - -variable "existing_sm_instance_guid" { - type = string - description = "An existing Secrets Manager GUID. The existing Secret Manager instance must have private certificate engine configured. If not provided an new instance will be provisioned." - default = null -} - -variable "existing_sm_instance_region" { - type = string - description = "Required if value is passed into `var.existing_sm_instance_guid`." - default = null -} - -variable "existing_cert_secret_id" { - type = string - description = "Required if value is passed into `var.existing_sm_instance_guid`." - default = null -} diff --git a/tests/resources/version.tf b/tests/resources/version.tf deleted file mode 100644 index 893cc71e..00000000 --- a/tests/resources/version.tf +++ /dev/null @@ -1,12 +0,0 @@ - -terraform { - required_version = ">= 1.3.0" - # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (this example), and 1 example that will always use the latest provider version (jobs examples). - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = ">= 1.70.0, < 2.0.0" - } - } -} From fcc12bae8bdddd14b632c2d37eda289a1469289c Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 12:55:30 +0000 Subject: [PATCH 6/9] remove unused code and add tests --- tests/pr_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index 0a5143a8..b17a1824 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -62,7 +62,7 @@ func setupAppsExampleOptions(t *testing.T, prefix string, terraformDir string) * options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, TemplateFolder: appsExampleDir, - Prefix: "ce-apps", + Prefix: prefix, TarIncludePatterns: []string{ "*.tf", appsExampleDir + "/*.tf", @@ -119,7 +119,7 @@ func TestRunUpgradeAppsExamplesInSchematics(t *testing.T) { } func TestRunJobsExample(t *testing.T) { - t.Parallel() + options := setupJobsExampleOptions(t, "ce-jobs", jobsExampleDir) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") @@ -127,7 +127,7 @@ func TestRunJobsExample(t *testing.T) { } func TestRunJobsUpgradeExample(t *testing.T) { - t.Parallel() + options := setupJobsExampleOptions(t, "ce-jobs-upg", jobsExampleDir) output, err := options.RunTestUpgrade() if !options.UpgradeTestSkipped { @@ -173,7 +173,7 @@ func TestRunBuildExampleInSchematics(t *testing.T) { } func TestRunBuildExample(t *testing.T) { - t.Parallel() + options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ Testing: t, TerraformDir: buildExampleDir, From 5b60ee368e72bade04054fec2d9fc6501aec6513 Mon Sep 17 00:00:00 2001 From: akocbek Date: Mon, 17 Nov 2025 09:36:01 +0000 Subject: [PATCH 7/9] merge conflicts --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 66d8c256..536b968c 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ This module provisions the IBM Cloud Code Engine fully managed and serverless pl * [secret](./modules/secret) * [Examples](./examples) *
Deploy to IBM Cloud button
+ *
Deploy to IBM Cloud button
*
Deploy to IBM Cloud button
* [Contributing](#contributing) From 70025e654e7fea31358a672ec951ac943f0c0567 Mon Sep 17 00:00:00 2001 From: akocbek Date: Tue, 25 Nov 2025 11:48:08 +0000 Subject: [PATCH 8/9] revert change --- examples/build/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build/main.tf b/examples/build/main.tf index 1e4666e3..11dd9691 100644 --- a/examples/build/main.tf +++ b/examples/build/main.tf @@ -4,7 +4,7 @@ module "resource_group" { source = "terraform-ibm-modules/resource-group/ibm" - version = "1.3.0" + version = "1.4.0" # if an existing resource group is not set (null) create a new one using prefix resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null existing_resource_group_name = var.resource_group From 365a9722db594fece5ea4ec73aaa77ffbd6cc980 Mon Sep 17 00:00:00 2001 From: akocbek Date: Tue, 25 Nov 2025 11:58:34 +0000 Subject: [PATCH 9/9] add new submodule --- common-dev-assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-dev-assets b/common-dev-assets index 29b7b43c..191c3ec3 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 29b7b43c9dd3183bbfcde228929b9e5f64b33f2a +Subproject commit 191c3ec328a8bc402b28104c9ed5249ee5fafab3