From 297b07190f548d417e6466d478459ed21feb79d2 Mon Sep 17 00:00:00 2001 From: ikkz Date: Sun, 10 May 2026 06:00:43 +0800 Subject: [PATCH] feat(git-clone): add pre_clone_script parameter (#887) ## Summary Add `pre_clone_script` parameter to the git-clone module, allowing users to run custom scripts before cloning a repository. ## Use Case This solves SSH host key verification issues (e.g., "Host key verification failed") by enabling users to configure SSH settings before the clone operation, such as adding known hosts or setting `StrictHostKeyChecking no`. ```tf module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" version = "1.3.0" agent_id = coder_agent.example.id url = "git@github.com:org/repo.git" pre_clone_script = <<-EOT #!/bin/bash mkdir -p ~/.ssh echo -e "Host github.com\n StrictHostKeyChecking no\n" > ~/.ssh/config chmod 600 ~/.ssh/config EOT } ``` Ref: https://discord.com/channels/747933592273027093/1447777180695396452/1447777180695396452 ## Type of Change - [ ] New module - [ ] New template - [ ] Bug fix - [x] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder/modules/git-clone` **New version:** `v1.3.0` **Breaking change:** [ ] Yes [x] No ## Testing & Validation - [x] Tests pass (`bun test`) - [x] Code formatted (`bun fmt`) - [x] Changes tested locally Co-authored-by: DevCats --- registry/coder/modules/git-clone/README.md | 45 ++++++++++++++----- registry/coder/modules/git-clone/main.test.ts | 12 +++++ registry/coder/modules/git-clone/main.tf | 9 ++++ registry/coder/modules/git-clone/run.sh | 11 +++++ 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/registry/coder/modules/git-clone/README.md b/registry/coder/modules/git-clone/README.md index b4f2a75c..9c61941c 100644 --- a/registry/coder/modules/git-clone/README.md +++ b/registry/coder/modules/git-clone/README.md @@ -14,7 +14,7 @@ This module allows you to automatically clone a repository by URL and skip if it module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" } @@ -28,7 +28,7 @@ module "git-clone" { module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" base_dir = "~/projects/coder" @@ -43,7 +43,7 @@ To use with [Git Authentication](https://coder.com/docs/v2/latest/admin/git-prov module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" } @@ -70,7 +70,7 @@ data "coder_parameter" "git_repo" { module "git_clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = data.coder_parameter.git_repo.value } @@ -105,7 +105,7 @@ Configuring `git-clone` for a self-hosted GitHub Enterprise Server running at `g module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.example.com/coder/coder/tree/feat/example" git_providers = { @@ -125,7 +125,7 @@ To GitLab clone with a specific branch like `feat/example` module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://gitlab.com/coder/coder/-/tree/feat/example" } @@ -137,7 +137,7 @@ Configuring `git-clone` for a self-hosted GitLab running at `gitlab.example.com` module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://gitlab.example.com/coder/coder/-/tree/feat/example" git_providers = { @@ -159,7 +159,7 @@ For example, to clone the `feat/example` branch: module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" branch_name = "feat/example" @@ -177,7 +177,7 @@ For example, this will clone into the `~/projects/coder/coder-dev` folder: module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" folder_name = "coder-dev" @@ -196,13 +196,36 @@ If not defined, the default, `0`, performs a full clone. module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" depth = 1 } ``` +## Pre-clone script + +Run a custom script before cloning the repository by setting the `pre_clone_script` variable. +This is useful for preparing the environment or validating prerequisites before cloning. + +```tf +module "git-clone" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/git-clone/coder" + version = "1.3.0" + agent_id = coder_agent.example.id + url = "https://github.com/coder/coder" + pre_clone_script = <<-EOT + #!/bin/bash + echo "Preparing to clone repository..." + # Check prerequisites + command -v npm >/dev/null 2>&1 || { echo "npm is required but not installed."; exit 1; } + # Set up environment + export NODE_ENV=development + EOT +} +``` + ## Post-clone script Run a custom script after cloning the repository by setting the `post_clone_script` variable. @@ -212,7 +235,7 @@ This is useful for running initialization tasks like installing dependencies or module "git-clone" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/git-clone/coder" - version = "1.2.3" + version = "1.3.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" post_clone_script = <<-EOT diff --git a/registry/coder/modules/git-clone/main.test.ts b/registry/coder/modules/git-clone/main.test.ts index 0ae0a8db..922f4028 100644 --- a/registry/coder/modules/git-clone/main.test.ts +++ b/registry/coder/modules/git-clone/main.test.ts @@ -261,4 +261,16 @@ describe("git-clone", async () => { expect(output.stdout).toContain("Running post-clone script..."); expect(output.stdout).toContain("Post-clone script executed"); }); + + it("runs pre-clone script", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + url: "fake-url", + pre_clone_script: "echo 'Pre-clone script executed'", + }); + const output = await executeScriptInContainer(state, "alpine/git"); + expect(output.stdout).toContain("Running pre-clone script..."); + expect(output.stdout).toContain("Pre-clone script executed"); + expect(output.stdout).toContain("Cloning fake-url to ~/fake-url..."); + }); }); diff --git a/registry/coder/modules/git-clone/main.tf b/registry/coder/modules/git-clone/main.tf index 2d547ad2..1fb28a4d 100644 --- a/registry/coder/modules/git-clone/main.tf +++ b/registry/coder/modules/git-clone/main.tf @@ -68,6 +68,12 @@ variable "post_clone_script" { default = null } +variable "pre_clone_script" { + description = "Custom script to run before cloning the repository. Runs before git clone, even if the repository already exists." + type = string + default = null +} + locals { # Remove query parameters and fragments from the URL url = replace(replace(var.url, "/\\?.*/", ""), "/#.*/", "") @@ -89,6 +95,8 @@ locals { web_url = startswith(local.clone_url, "git@") ? replace(replace(local.clone_url, ":", "/"), "git@", "https://") : local.clone_url # Encode the post_clone_script for passing to the shell script encoded_post_clone_script = var.post_clone_script != null ? base64encode(var.post_clone_script) : "" + # Encode the pre_clone_script for passing to the shell script + encoded_pre_clone_script = var.pre_clone_script != null ? base64encode(var.pre_clone_script) : "" } output "repo_dir" { @@ -129,6 +137,7 @@ resource "coder_script" "git_clone" { BRANCH_NAME : local.branch_name, DEPTH = var.depth, POST_CLONE_SCRIPT : local.encoded_post_clone_script, + PRE_CLONE_SCRIPT : local.encoded_pre_clone_script, }) display_name = "Git Clone" icon = "/icon/git.svg" diff --git a/registry/coder/modules/git-clone/run.sh b/registry/coder/modules/git-clone/run.sh index c088e4d0..03050349 100644 --- a/registry/coder/modules/git-clone/run.sh +++ b/registry/coder/modules/git-clone/run.sh @@ -7,6 +7,7 @@ BRANCH_NAME="${BRANCH_NAME}" CLONE_PATH="$${CLONE_PATH/#\~/$${HOME}}" DEPTH="${DEPTH}" POST_CLONE_SCRIPT="${POST_CLONE_SCRIPT}" +PRE_CLONE_SCRIPT="${PRE_CLONE_SCRIPT}" # Check if the variable is empty... if [ -z "$REPO_URL" ]; then @@ -33,6 +34,16 @@ if [ ! -d "$CLONE_PATH" ]; then mkdir -p "$CLONE_PATH" fi +# Run pre-clone script if provided +if [ -n "$PRE_CLONE_SCRIPT" ]; then + echo "Running pre-clone script..." + PRE_CLONE_TMP=$(mktemp) + echo "$PRE_CLONE_SCRIPT" | base64 -d > "$PRE_CLONE_TMP" + chmod +x "$PRE_CLONE_TMP" + $PRE_CLONE_TMP + rm "$PRE_CLONE_TMP" +fi + # Check if the directory is empty # and if it is, clone the repo, otherwise skip cloning if [ -z "$(ls -A "$CLONE_PATH")" ]; then