From 662ec4f16e01190b0d17d42cc697c9a3a8eb5858 Mon Sep 17 00:00:00 2001 From: akocbek Date: Thu, 16 Oct 2025 13:38:09 +0100 Subject: [PATCH 1/6] 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/6] update merge conflicts --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66e3bfec..60e7507a 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 915b70028f00b89210e37bb07f189b1f14810a30 Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 09:06:08 +0000 Subject: [PATCH 3/6] address PR comments --- README.md | 1 + modules/build/main.tf | 8 +++++--- modules/build/variables.tf | 18 ++++++++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 60e7507a..6c66ab01 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) *
Apps example
Deploy to IBM Cloud button
+ *
Build example
Deploy to IBM Cloud button
*
Jobs example
Deploy to IBM Cloud button
* [Contributing](#contributing) 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 e117634ecb5d91ebba634a9959c342da0e318a61 Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 09:09:46 +0000 Subject: [PATCH 4/6] 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 e594fd826119f8690efc7be4600abbd957e65127 Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 11:17:00 +0000 Subject: [PATCH 5/6] 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 46bee3a1..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.4" - 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 511e1f616e9e81c9a8028134ca0001170ac703ad Mon Sep 17 00:00:00 2001 From: akocbek Date: Fri, 14 Nov 2025 12:55:30 +0000 Subject: [PATCH 6/6] 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,