feat(registry/coder/modules/coder-utils): make install_script and start_script optional (#842)
Co-authored-by: Jay Kumar <jay.kumar@coder.com> Co-authored-by: Atif Ali <atif@coder.com>
This commit is contained in:
parent
b108185c14
commit
39f332fcaf
@ -20,11 +20,11 @@ The Coder Utils module is a building block for modules that need to run multiple
|
||||
```tf
|
||||
module "coder_utils" {
|
||||
source = "registry.coder.com/coder/coder-utils/coder"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "myagent"
|
||||
module_dir_name = ".my-module"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "myagent"
|
||||
module_directory = ".my-module"
|
||||
|
||||
pre_install_script = <<-EOT
|
||||
#!/bin/bash
|
||||
@ -56,10 +56,30 @@ module "coder_utils" {
|
||||
|
||||
The module orchestrates scripts in the following order:
|
||||
|
||||
1. **Log File Creation** - Creates module directory and log files
|
||||
2. **Pre-Install Script** (optional) - Runs before installation
|
||||
3. **Install Script** - Main installation
|
||||
4. **Post-Install Script** (optional) - Runs after installation
|
||||
5. **Start Script** - Starts the application
|
||||
1. **Pre-Install Script** (optional) - Runs before installation
|
||||
2. **Install Script** (required) - Main installation
|
||||
3. **Post-Install Script** (optional) - Runs after installation
|
||||
4. **Start Script** (optional) - Starts the application
|
||||
|
||||
Each script waits for its prerequisites to complete before running using `coder exp sync` dependency management.
|
||||
|
||||
## Customizing Script Display
|
||||
|
||||
By default each `coder_script` renders in the Coder UI as plain "Install Script", "Pre-Install Script", etc. Downstream modules can brand them:
|
||||
|
||||
```tf
|
||||
module "coder_utils" {
|
||||
source = "registry.coder.com/coder/coder-utils/coder"
|
||||
version = "1.1.0"
|
||||
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "myagent"
|
||||
module_directory = ".my-module"
|
||||
install_script = "echo installing"
|
||||
|
||||
display_name_prefix = "Claude Code" # yields "Claude Code: Install Script", etc.
|
||||
icon = "/icon/claude.svg"
|
||||
}
|
||||
```
|
||||
|
||||
Both variables are optional. `display_name_prefix` defaults to `""` (no prefix), and `icon` defaults to `null` (use the Coder provider's default).
|
||||
|
||||
@ -7,7 +7,7 @@ describe("coder-utils", async () => {
|
||||
testRequiredVariables(import.meta.dir, {
|
||||
agent_id: "test-agent-id",
|
||||
agent_name: "test-agent",
|
||||
module_dir_name: ".test-module",
|
||||
start_script: "echo 'start'",
|
||||
module_directory: ".test-module",
|
||||
install_script: "echo 'install'",
|
||||
});
|
||||
});
|
||||
|
||||
@ -29,7 +29,6 @@ variable "pre_install_script" {
|
||||
variable "install_script" {
|
||||
type = string
|
||||
description = "Script to install the agent used by AgentAPI."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "post_install_script" {
|
||||
@ -41,6 +40,7 @@ variable "post_install_script" {
|
||||
variable "start_script" {
|
||||
type = string
|
||||
description = "Script that starts AgentAPI."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "agent_name" {
|
||||
@ -49,46 +49,67 @@ variable "agent_name" {
|
||||
|
||||
}
|
||||
|
||||
variable "module_dir_name" {
|
||||
variable "module_directory" {
|
||||
type = string
|
||||
description = "The name of the module directory."
|
||||
description = "The module's working directory for scripts and logs."
|
||||
}
|
||||
|
||||
variable "display_name_prefix" {
|
||||
type = string
|
||||
description = "Prefix for each coder_script display_name. Example: setting 'Claude Code' yields 'Claude Code: Install Script', 'Claude Code: Pre-Install Script', etc. When unset, scripts show as plain 'Install Script'."
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "icon" {
|
||||
type = string
|
||||
description = "Icon shown in the Coder UI for every coder_script this module creates. Falls back to the Coder provider's default when unset."
|
||||
default = null
|
||||
}
|
||||
|
||||
locals {
|
||||
encoded_pre_install_script = var.pre_install_script != null ? base64encode(var.pre_install_script) : ""
|
||||
encoded_install_script = var.install_script != null ? base64encode(var.install_script) : ""
|
||||
encoded_install_script = base64encode(var.install_script)
|
||||
encoded_post_install_script = var.post_install_script != null ? base64encode(var.post_install_script) : ""
|
||||
encoded_start_script = base64encode(var.start_script)
|
||||
encoded_start_script = var.start_script != null ? base64encode(var.start_script) : ""
|
||||
|
||||
pre_install_script_name = "${var.agent_name}-pre_install_script"
|
||||
install_script_name = "${var.agent_name}-install_script"
|
||||
post_install_script_name = "${var.agent_name}-post_install_script"
|
||||
start_script_name = "${var.agent_name}-start_script"
|
||||
|
||||
module_dir_path = "$HOME/${var.module_dir_name}"
|
||||
pre_install_path = "${var.module_directory}/pre_install.sh"
|
||||
install_path = "${var.module_directory}/install.sh"
|
||||
post_install_path = "${var.module_directory}/post_install.sh"
|
||||
start_path = "${var.module_directory}/start.sh"
|
||||
|
||||
pre_install_path = "${local.module_dir_path}/pre_install.sh"
|
||||
install_path = "${local.module_dir_path}/install.sh"
|
||||
post_install_path = "${local.module_dir_path}/post_install.sh"
|
||||
start_path = "${local.module_dir_path}/start.sh"
|
||||
pre_install_log_path = "${var.module_directory}/pre_install.log"
|
||||
install_log_path = "${var.module_directory}/install.log"
|
||||
post_install_log_path = "${var.module_directory}/post_install.log"
|
||||
start_log_path = "${var.module_directory}/start.log"
|
||||
|
||||
pre_install_log_path = "${local.module_dir_path}/pre_install.log"
|
||||
install_log_path = "${local.module_dir_path}/install.log"
|
||||
post_install_log_path = "${local.module_dir_path}/post_install.log"
|
||||
start_log_path = "${local.module_dir_path}/start.log"
|
||||
install_sync_deps = var.pre_install_script != null ? local.pre_install_script_name : null
|
||||
|
||||
start_sync_deps = (
|
||||
var.post_install_script != null
|
||||
? "${local.install_script_name} ${local.post_install_script_name}"
|
||||
: local.install_script_name
|
||||
)
|
||||
|
||||
display_name_prefix = var.display_name_prefix != "" ? "${var.display_name_prefix}: " : ""
|
||||
}
|
||||
|
||||
resource "coder_script" "pre_install_script" {
|
||||
count = var.pre_install_script == null ? 0 : 1
|
||||
agent_id = var.agent_id
|
||||
display_name = "Pre-Install Script"
|
||||
display_name = "${local.display_name_prefix}Pre-Install Script"
|
||||
icon = var.icon
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
mkdir -p ${local.module_dir_path}
|
||||
mkdir -p ${var.module_directory}
|
||||
|
||||
trap 'coder exp sync complete ${local.pre_install_script_name}' EXIT
|
||||
coder exp sync start ${local.pre_install_script_name}
|
||||
@ -96,37 +117,39 @@ resource "coder_script" "pre_install_script" {
|
||||
echo -n '${local.encoded_pre_install_script}' | base64 -d > ${local.pre_install_path}
|
||||
chmod +x ${local.pre_install_path}
|
||||
|
||||
${local.pre_install_path} > ${local.pre_install_log_path} 2>&1
|
||||
${local.pre_install_path} 2>&1 | tee ${local.pre_install_log_path}
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "coder_script" "install_script" {
|
||||
agent_id = var.agent_id
|
||||
display_name = "Install Script"
|
||||
display_name = "${local.display_name_prefix}Install Script"
|
||||
icon = var.icon
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
mkdir -p ${local.module_dir_path}
|
||||
mkdir -p ${var.module_directory}
|
||||
|
||||
trap 'coder exp sync complete ${local.install_script_name}' EXIT
|
||||
%{if var.pre_install_script != null~}
|
||||
coder exp sync want ${local.install_script_name} ${local.pre_install_script_name}
|
||||
%{if local.install_sync_deps != null~}
|
||||
coder exp sync want ${local.install_script_name} ${local.install_sync_deps}
|
||||
%{endif~}
|
||||
coder exp sync start ${local.install_script_name}
|
||||
echo -n '${local.encoded_install_script}' | base64 -d > ${local.install_path}
|
||||
chmod +x ${local.install_path}
|
||||
|
||||
${local.install_path} > ${local.install_log_path} 2>&1
|
||||
${local.install_path} 2>&1 | tee ${local.install_log_path}
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "coder_script" "post_install_script" {
|
||||
count = var.post_install_script != null ? 1 : 0
|
||||
agent_id = var.agent_id
|
||||
display_name = "Post-Install Script"
|
||||
display_name = "${local.display_name_prefix}Post-Install Script"
|
||||
icon = var.icon
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
@ -140,13 +163,15 @@ resource "coder_script" "post_install_script" {
|
||||
echo -n '${local.encoded_post_install_script}' | base64 -d > ${local.post_install_path}
|
||||
chmod +x ${local.post_install_path}
|
||||
|
||||
${local.post_install_path} > ${local.post_install_log_path} 2>&1
|
||||
${local.post_install_path} 2>&1 | tee ${local.post_install_log_path}
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "coder_script" "start_script" {
|
||||
count = var.start_script != null ? 1 : 0
|
||||
agent_id = var.agent_id
|
||||
display_name = "Start Script"
|
||||
display_name = "${local.display_name_prefix}Start Script"
|
||||
icon = var.icon
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
@ -155,36 +180,28 @@ resource "coder_script" "start_script" {
|
||||
|
||||
trap 'coder exp sync complete ${local.start_script_name}' EXIT
|
||||
|
||||
%{if var.post_install_script != null~}
|
||||
coder exp sync want ${local.start_script_name} ${local.install_script_name} ${local.post_install_script_name}
|
||||
%{else~}
|
||||
coder exp sync want ${local.start_script_name} ${local.install_script_name}
|
||||
%{endif~}
|
||||
coder exp sync want ${local.start_script_name} ${local.start_sync_deps}
|
||||
coder exp sync start ${local.start_script_name}
|
||||
|
||||
echo -n '${local.encoded_start_script}' | base64 -d > ${local.start_path}
|
||||
chmod +x ${local.start_path}
|
||||
|
||||
${local.start_path} > ${local.start_log_path} 2>&1
|
||||
${local.start_path} 2>&1 | tee ${local.start_log_path}
|
||||
EOT
|
||||
}
|
||||
|
||||
output "pre_install_script_name" {
|
||||
description = "The name of the pre-install script for sync."
|
||||
value = local.pre_install_script_name
|
||||
}
|
||||
|
||||
output "install_script_name" {
|
||||
description = "The name of the install script for sync."
|
||||
value = local.install_script_name
|
||||
}
|
||||
|
||||
output "post_install_script_name" {
|
||||
description = "The name of the post-install script for sync."
|
||||
value = local.post_install_script_name
|
||||
}
|
||||
|
||||
output "start_script_name" {
|
||||
description = "The name of the start script for sync."
|
||||
value = local.start_script_name
|
||||
# Filtered, run-order list of the `coder exp sync` names for every
|
||||
# coder_script this module actually creates. Absent scripts (pre/post/start
|
||||
# when their inputs are null) are omitted entirely, not padded with empty
|
||||
# strings. Downstream modules can use this with
|
||||
# `coder exp sync want <self> <each of these>` to serialize their own
|
||||
# scripts behind the install pipeline.
|
||||
output "scripts" {
|
||||
description = "Ordered list of `coder exp sync` names for the coder_script resources this module creates, in the run order it enforces (pre_install, install, post_install, start). Scripts that were not configured are absent from the list."
|
||||
value = concat(
|
||||
var.pre_install_script != null ? [local.pre_install_script_name] : [],
|
||||
[local.install_script_name],
|
||||
var.post_install_script != null ? [local.post_install_script_name] : [],
|
||||
var.start_script != null ? [local.start_script_name] : [],
|
||||
)
|
||||
}
|
||||
@ -7,7 +7,7 @@ run "test_with_all_scripts" {
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_dir_name = ".test-module"
|
||||
module_directory = ".test-module"
|
||||
pre_install_script = "echo 'pre-install'"
|
||||
install_script = "echo 'install'"
|
||||
post_install_script = "echo 'post-install'"
|
||||
@ -35,7 +35,7 @@ run "test_with_all_scripts" {
|
||||
error_message = "Pre-install script should run on start"
|
||||
}
|
||||
|
||||
# Verify install_script is created
|
||||
# Verify install_script is always created
|
||||
assert {
|
||||
condition = coder_script.install_script.agent_id == "test-agent-id"
|
||||
error_message = "Install script agent ID should match input"
|
||||
@ -51,6 +51,12 @@ run "test_with_all_scripts" {
|
||||
error_message = "Install script should run on start"
|
||||
}
|
||||
|
||||
# install should sync-want pre_install
|
||||
assert {
|
||||
condition = can(regex("sync want test-agent-install_script test-agent-pre_install_script", coder_script.install_script.script))
|
||||
error_message = "Install script should sync-want pre_install_script when pre_install is provided"
|
||||
}
|
||||
|
||||
# Verify post_install_script is created when provided
|
||||
assert {
|
||||
condition = length(coder_script.post_install_script) == 1
|
||||
@ -72,98 +78,103 @@ run "test_with_all_scripts" {
|
||||
error_message = "Post-install script should run on start"
|
||||
}
|
||||
|
||||
# Verify start_script is created
|
||||
# Verify start_script is created when provided
|
||||
assert {
|
||||
condition = coder_script.start_script.agent_id == "test-agent-id"
|
||||
condition = length(coder_script.start_script) == 1
|
||||
error_message = "Start script should be created when start_script is provided"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script[0].agent_id == "test-agent-id"
|
||||
error_message = "Start script agent ID should match input"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script.display_name == "Start Script"
|
||||
condition = coder_script.start_script[0].display_name == "Start Script"
|
||||
error_message = "Start script should have correct display name"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script.run_on_start == true
|
||||
condition = coder_script.start_script[0].run_on_start == true
|
||||
error_message = "Start script should run on start"
|
||||
}
|
||||
|
||||
# Verify outputs for script names
|
||||
assert {
|
||||
condition = output.pre_install_script_name == "test-agent-pre_install_script"
|
||||
error_message = "Pre-install script name output should be correctly formatted"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.install_script_name == "test-agent-install_script"
|
||||
error_message = "Install script name output should be correctly formatted"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.post_install_script_name == "test-agent-post_install_script"
|
||||
error_message = "Post-install script name output should be correctly formatted"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.start_script_name == "test-agent-start_script"
|
||||
error_message = "Start script name output should be correctly formatted"
|
||||
}
|
||||
}
|
||||
|
||||
# Test with only required scripts (no pre/post install)
|
||||
run "test_without_optional_scripts" {
|
||||
# Test with only install_script (minimum required input)
|
||||
run "test_install_only" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_dir_name = ".test-module"
|
||||
install_script = "echo 'install'"
|
||||
start_script = "echo 'start'"
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo 'install'"
|
||||
}
|
||||
|
||||
# Verify pre_install_script is NOT created when not provided
|
||||
# Verify optional scripts are NOT created
|
||||
assert {
|
||||
condition = length(coder_script.pre_install_script) == 0
|
||||
error_message = "Pre-install script should not be created when pre_install_script is null"
|
||||
error_message = "Pre-install script should not be created when not provided"
|
||||
}
|
||||
|
||||
# Verify post_install_script is NOT created when not provided
|
||||
assert {
|
||||
condition = length(coder_script.post_install_script) == 0
|
||||
error_message = "Post-install script should not be created when post_install_script is null"
|
||||
error_message = "Post-install script should not be created when not provided"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(coder_script.start_script) == 0
|
||||
error_message = "Start script should not be created when not provided"
|
||||
}
|
||||
|
||||
# Verify install_script is created
|
||||
assert {
|
||||
condition = coder_script.install_script.agent_id == "test-agent-id"
|
||||
error_message = "Install script should be created"
|
||||
}
|
||||
}
|
||||
|
||||
# Test with install and start scripts (no pre/post install)
|
||||
run "test_install_and_start" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo 'install'"
|
||||
start_script = "echo 'start'"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(coder_script.pre_install_script) == 0
|
||||
error_message = "Pre-install script should not be created when not provided"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(coder_script.post_install_script) == 0
|
||||
error_message = "Post-install script should not be created when not provided"
|
||||
}
|
||||
|
||||
# Verify required scripts are still created
|
||||
assert {
|
||||
condition = coder_script.install_script.agent_id == "test-agent-id"
|
||||
error_message = "Install script should be created"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script.agent_id == "test-agent-id"
|
||||
condition = length(coder_script.start_script) == 1
|
||||
error_message = "Start script should be created"
|
||||
}
|
||||
|
||||
# Verify outputs
|
||||
assert {
|
||||
condition = output.pre_install_script_name == "test-agent-pre_install_script"
|
||||
error_message = "Pre-install script name output should be generated even when script is not created"
|
||||
condition = coder_script.start_script[0].agent_id == "test-agent-id"
|
||||
error_message = "Start script agent ID should match input"
|
||||
}
|
||||
|
||||
# start should sync-want install (no post_install)
|
||||
assert {
|
||||
condition = output.install_script_name == "test-agent-install_script"
|
||||
error_message = "Install script name output should be correctly formatted"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.post_install_script_name == "test-agent-post_install_script"
|
||||
error_message = "Post-install script name output should be generated even when script is not created"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.start_script_name == "test-agent-start_script"
|
||||
error_message = "Start script name output should be correctly formatted"
|
||||
condition = can(regex("sync want test-agent-start_script test-agent-install_script", coder_script.start_script[0].script))
|
||||
error_message = "Start script should sync-want install_script"
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,14 +183,13 @@ run "test_with_mock_data" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "mock-agent"
|
||||
agent_name = "mock-agent"
|
||||
module_dir_name = ".mock-module"
|
||||
install_script = "echo 'install'"
|
||||
start_script = "echo 'start'"
|
||||
agent_id = "mock-agent"
|
||||
agent_name = "mock-agent"
|
||||
module_directory = ".mock-module"
|
||||
install_script = "echo 'install'"
|
||||
start_script = "echo 'start'"
|
||||
}
|
||||
|
||||
# Mock the data sources for testing
|
||||
override_data {
|
||||
target = data.coder_workspace.me
|
||||
values = {
|
||||
@ -212,14 +222,13 @@ run "test_with_mock_data" {
|
||||
}
|
||||
}
|
||||
|
||||
# Verify scripts are created with mocked data
|
||||
assert {
|
||||
condition = coder_script.install_script.agent_id == "mock-agent"
|
||||
error_message = "Install script should use the mocked agent ID"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script.agent_id == "mock-agent"
|
||||
condition = coder_script.start_script[0].agent_id == "mock-agent"
|
||||
error_message = "Start script should use the mocked agent ID"
|
||||
}
|
||||
}
|
||||
@ -229,43 +238,294 @@ run "test_script_naming" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent"
|
||||
agent_name = "custom-name"
|
||||
module_dir_name = ".test-module"
|
||||
install_script = "echo 'install'"
|
||||
start_script = "echo 'start'"
|
||||
agent_id = "test-agent"
|
||||
agent_name = "custom-name"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo 'install'"
|
||||
start_script = "echo 'start'"
|
||||
}
|
||||
|
||||
# Verify script names are constructed correctly
|
||||
# The script should contain references to custom-name-* in the sync commands
|
||||
assert {
|
||||
condition = can(regex("custom-name-install_script", coder_script.install_script.script))
|
||||
error_message = "Install script should use custom agent_name in sync commands"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = can(regex("custom-name-start_script", coder_script.start_script.script))
|
||||
condition = can(regex("custom-name-start_script", coder_script.start_script[0].script))
|
||||
error_message = "Start script should use custom agent_name in sync commands"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify outputs use custom agent_name
|
||||
assert {
|
||||
condition = output.pre_install_script_name == "custom-name-pre_install_script"
|
||||
error_message = "Pre-install script name output should use custom agent_name"
|
||||
# Test install syncs with pre_install when provided
|
||||
run "test_install_syncs_with_pre_install" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
pre_install_script = "echo 'pre-install'"
|
||||
install_script = "echo 'install'"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.install_script_name == "custom-name-install_script"
|
||||
error_message = "Install script name output should use custom agent_name"
|
||||
condition = length(coder_script.pre_install_script) == 1
|
||||
error_message = "Pre-install script should be created"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.post_install_script_name == "custom-name-post_install_script"
|
||||
error_message = "Post-install script name output should use custom agent_name"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.start_script_name == "custom-name-start_script"
|
||||
error_message = "Start script name output should use custom agent_name"
|
||||
condition = can(regex("sync want test-agent-install_script test-agent-pre_install_script", coder_script.install_script.script))
|
||||
error_message = "Install script should sync-want pre_install_script"
|
||||
}
|
||||
}
|
||||
|
||||
# Test start script sync deps with post_install present
|
||||
run "test_start_syncs_with_post_install" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo 'install'"
|
||||
post_install_script = "echo 'post-install'"
|
||||
start_script = "echo 'start'"
|
||||
}
|
||||
|
||||
# start should sync-want both install and post_install
|
||||
assert {
|
||||
condition = can(regex("sync want test-agent-start_script test-agent-install_script test-agent-post_install_script", coder_script.start_script[0].script))
|
||||
error_message = "Start script should sync-want both install_script and post_install_script"
|
||||
}
|
||||
|
||||
# post_install should sync-want install
|
||||
assert {
|
||||
condition = can(regex("sync want test-agent-post_install_script test-agent-install_script", coder_script.post_install_script[0].script))
|
||||
error_message = "Post-install script should sync-want install_script"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify display_name_prefix is prepended to every script's display_name
|
||||
run "test_display_name_prefix_applied" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
display_name_prefix = "Claude Code"
|
||||
pre_install_script = "echo 'pre-install'"
|
||||
install_script = "echo 'install'"
|
||||
post_install_script = "echo 'post-install'"
|
||||
start_script = "echo 'start'"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.pre_install_script[0].display_name == "Claude Code: Pre-Install Script"
|
||||
error_message = "Pre-install script display_name should be prefixed"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.install_script.display_name == "Claude Code: Install Script"
|
||||
error_message = "Install script display_name should be prefixed"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.post_install_script[0].display_name == "Claude Code: Post-Install Script"
|
||||
error_message = "Post-install script display_name should be prefixed"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script[0].display_name == "Claude Code: Start Script"
|
||||
error_message = "Start script display_name should be prefixed"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify icon is propagated to every coder_script
|
||||
run "test_icon_applied" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
icon = "/icon/claude.svg"
|
||||
pre_install_script = "echo 'pre-install'"
|
||||
install_script = "echo 'install'"
|
||||
post_install_script = "echo 'post-install'"
|
||||
start_script = "echo 'start'"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.pre_install_script[0].icon == "/icon/claude.svg"
|
||||
error_message = "Pre-install script icon should match input"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.install_script.icon == "/icon/claude.svg"
|
||||
error_message = "Install script icon should match input"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.post_install_script[0].icon == "/icon/claude.svg"
|
||||
error_message = "Post-install script icon should match input"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = coder_script.start_script[0].icon == "/icon/claude.svg"
|
||||
error_message = "Start script icon should match input"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify optional scripts are not created when their variables are unset
|
||||
run "test_optional_scripts_absent_by_default" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo install"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(coder_script.pre_install_script) == 0
|
||||
error_message = "Pre-install coder_script should not be created when pre_install_script is unset"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(coder_script.post_install_script) == 0
|
||||
error_message = "Post-install coder_script should not be created when post_install_script is unset"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(coder_script.start_script) == 0
|
||||
error_message = "Start coder_script should not be created when start_script is unset"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify `scripts` output is a filtered, run-order list
|
||||
run "test_scripts_output_with_all" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
pre_install_script = "echo pre"
|
||||
install_script = "echo install"
|
||||
post_install_script = "echo post"
|
||||
start_script = "echo start"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(output.scripts) == 4
|
||||
error_message = "scripts should have 4 entries when every script is set"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[0] == "test-agent-pre_install_script"
|
||||
error_message = "scripts[0] must be the pre-install name"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[1] == "test-agent-install_script"
|
||||
error_message = "scripts[1] must be the install name"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[2] == "test-agent-post_install_script"
|
||||
error_message = "scripts[2] must be the post-install name"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[3] == "test-agent-start_script"
|
||||
error_message = "scripts[3] must be the start name"
|
||||
}
|
||||
}
|
||||
|
||||
run "test_scripts_output_with_install_only" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo install"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(output.scripts) == 1
|
||||
error_message = "scripts should have exactly 1 entry (install) when pre/post/start are unset"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[0] == "test-agent-install_script"
|
||||
error_message = "scripts[0] must be the install name"
|
||||
}
|
||||
}
|
||||
|
||||
run "test_scripts_output_with_install_and_post" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
install_script = "echo install"
|
||||
post_install_script = "echo post"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = length(output.scripts) == 2
|
||||
error_message = "scripts should have 2 entries (install, post)"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[0] == "test-agent-install_script"
|
||||
error_message = "scripts[0] must be the install name"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.scripts[1] == "test-agent-post_install_script"
|
||||
error_message = "scripts[1] must be the post-install name"
|
||||
}
|
||||
}
|
||||
|
||||
# Every script must stream combined stdout+stderr to both the agent log
|
||||
# (via stdout) and the on-disk log file (via tee), so workspace users
|
||||
# watching `coder_script` output in the UI see progress live and can
|
||||
# read the same content from the log file after the fact.
|
||||
run "test_scripts_tee_stdout_and_log_file" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-id"
|
||||
agent_name = "test-agent"
|
||||
module_directory = ".test-module"
|
||||
pre_install_script = "echo pre"
|
||||
install_script = "echo install"
|
||||
post_install_script = "echo post"
|
||||
start_script = "echo start"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = can(regex("pre_install.sh 2>&1 \\| tee .*pre_install.log", coder_script.pre_install_script[0].script))
|
||||
error_message = "pre_install wrapper must tee combined output to the log file and stdout"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = can(regex("install.sh 2>&1 \\| tee .*install.log", coder_script.install_script.script))
|
||||
error_message = "install wrapper must tee combined output to the log file and stdout"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = can(regex("post_install.sh 2>&1 \\| tee .*post_install.log", coder_script.post_install_script[0].script))
|
||||
error_message = "post_install wrapper must tee combined output to the log file and stdout"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = can(regex("start.sh 2>&1 \\| tee .*start.log", coder_script.start_script[0].script))
|
||||
error_message = "start wrapper must tee combined output to the log file and stdout"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user