From 9d2e19de1a61032b8088abe930d2108240431d29 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 19 May 2026 06:32:24 +0000 Subject: [PATCH] feat(git-clone): replace depth, recurse_submodules, and clone_jobs with extra_args for flexible git clone options --- registry/coder/modules/git-clone/README.md | 37 +++++--------- registry/coder/modules/git-clone/main.test.ts | 48 +++---------------- registry/coder/modules/git-clone/main.tf | 36 ++++---------- registry/coder/modules/git-clone/run.sh | 16 ++----- 4 files changed, 31 insertions(+), 106 deletions(-) diff --git a/registry/coder/modules/git-clone/README.md b/registry/coder/modules/git-clone/README.md index 4490521f..2d3a1a82 100644 --- a/registry/coder/modules/git-clone/README.md +++ b/registry/coder/modules/git-clone/README.md @@ -185,12 +185,12 @@ module "git-clone" { } ``` -## Git shallow clone +## Extra `git clone` arguments -Limit the clone history to speed-up workspace startup by setting `depth`. - -When `depth` is greater than `0` the module runs `git clone --depth `. -If not defined, the default, `0`, performs a full clone. +Pass any additional flags through `extra_args` (one element per argument). +This lets you enable anything `git clone` supports without the module having +to expose it explicitly — for example a shallow clone, submodules, parallel +fetches, or partial clones. ```tf module "git-clone" { @@ -199,27 +199,12 @@ module "git-clone" { version = "1.4.0" agent_id = coder_agent.example.id url = "https://github.com/coder/coder" - depth = 1 -} -``` - -## Recurse submodules - -Set `recurse_submodules = true` to initialize and clone submodules during the -clone (equivalent to `git clone --recurse-submodules`). - -Pair it with `clone_jobs` to fetch submodules in parallel (equivalent to -`git clone --jobs `) and speed up workspace start. - -```tf -module "git-clone" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/git-clone/coder" - version = "1.4.0" - agent_id = coder_agent.example.id - url = "https://github.com/coder/coder" - recurse_submodules = true - clone_jobs = 8 + extra_args = [ + "--depth=1", + "--recurse-submodules", + "--jobs=8", + "--filter=blob:none", + ] } ``` diff --git a/registry/coder/modules/git-clone/main.test.ts b/registry/coder/modules/git-clone/main.test.ts index 9e1ddea1..93eaa32a 100644 --- a/registry/coder/modules/git-clone/main.test.ts +++ b/registry/coder/modules/git-clone/main.test.ts @@ -316,58 +316,24 @@ describe("git-clone", async () => { ); }); - it("defaults recurse_submodules to false and clone_jobs to 0", async () => { + it("defaults extra_args to empty", async () => { const state = await runTerraformApply(import.meta.dir, { agent_id: "foo", url: "fake-url", }); const script = findResourceInstance(state, "coder_script").script; - expect(script).toContain('RECURSE_SUBMODULES="false"'); - expect(script).toContain('CLONE_JOBS="0"'); + expect(script).toContain('EXTRA_ARGS_B64=""'); }); - it("sets RECURSE_SUBMODULES=true when recurse_submodules is enabled", async () => { + it("passes extra_args to git clone", async () => { const state = await runTerraformApply(import.meta.dir, { agent_id: "foo", url: "fake-url", - recurse_submodules: "true", + extra_args: '["--recurse-submodules", "--jobs=8"]', }); - const script = findResourceInstance(state, "coder_script").script; - expect(script).toContain('RECURSE_SUBMODULES="true"'); - }); - - it("sets CLONE_JOBS when clone_jobs > 0", async () => { - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - url: "fake-url", - recurse_submodules: "true", - clone_jobs: "8", - }); - const script = findResourceInstance(state, "coder_script").script; - expect(script).toContain('CLONE_JOBS="8"'); - }); - - it("rejects non-positive clone_jobs", async () => { - const t = async () => { - await runTerraformApply(import.meta.dir, { - agent_id: "foo", - url: "fake-url", - clone_jobs: "-1", - }); - }; - expect(t).toThrow("clone_jobs must be a positive integer when set."); - }); - - it("rejects clone_jobs without recurse_submodules", async () => { - const t = async () => { - await runTerraformApply(import.meta.dir, { - agent_id: "foo", - url: "fake-url", - clone_jobs: "4", - }); - }; - expect(t).toThrow( - "clone_jobs only affects submodule fetching, so it requires recurse_submodules", + const output = await executeScriptInContainer(state, "alpine/git"); + expect(output.stdout).toContain( + "Running: git clone --recurse-submodules --jobs=8 fake-url /root/fake-url", ); }); diff --git a/registry/coder/modules/git-clone/main.tf b/registry/coder/modules/git-clone/main.tf index ec5f1339..2a2f2e72 100644 --- a/registry/coder/modules/git-clone/main.tf +++ b/registry/coder/modules/git-clone/main.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.9" + required_version = ">= 1.0" required_providers { coder = { @@ -56,30 +56,10 @@ variable "folder_name" { default = "" } -variable "depth" { - description = "If > 0, perform a shallow clone using this depth." - type = number - default = 0 -} - -variable "recurse_submodules" { - description = "If true, clone submodules recursively (equivalent to `git clone --recurse-submodules`)." - type = bool - default = false -} - -variable "clone_jobs" { - description = "If set, fetch submodules in parallel using this many jobs (equivalent to `git clone --jobs `). Only takes effect when `recurse_submodules = true`." - type = number - default = null - validation { - condition = var.clone_jobs == null || var.clone_jobs > 0 - error_message = "clone_jobs must be a positive integer when set." - } - validation { - condition = var.clone_jobs == null || var.recurse_submodules - error_message = "clone_jobs only affects submodule fetching, so it requires recurse_submodules = true." - } +variable "extra_args" { + description = "Extra arguments to pass to `git clone`, one element per argument (e.g. `[\"--recurse-submodules\", \"--jobs=8\", \"--filter=blob:none\"]`)." + type = list(string) + default = [] } variable "post_clone_script" { @@ -117,6 +97,8 @@ locals { 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) : "" + # Encode extra clone args (newline-separated) so the shell script can split them into an array safely + encoded_extra_args = base64encode(join("\n", var.extra_args)) } output "repo_dir" { @@ -155,9 +137,7 @@ resource "coder_script" "git_clone" { CLONE_PATH = local.clone_path, REPO_URL : local.clone_url, BRANCH_NAME : local.branch_name, - DEPTH = var.depth, - RECURSE_SUBMODULES = tostring(var.recurse_submodules), - CLONE_JOBS = coalesce(var.clone_jobs, 0), + EXTRA_ARGS = local.encoded_extra_args, POST_CLONE_SCRIPT : local.encoded_post_clone_script, PRE_CLONE_SCRIPT : local.encoded_pre_clone_script, }) diff --git a/registry/coder/modules/git-clone/run.sh b/registry/coder/modules/git-clone/run.sh index db0fb373..752e84bc 100644 --- a/registry/coder/modules/git-clone/run.sh +++ b/registry/coder/modules/git-clone/run.sh @@ -7,9 +7,7 @@ CLONE_PATH="${CLONE_PATH}" BRANCH_NAME="${BRANCH_NAME}" # Expand home if it's specified! CLONE_PATH="$${CLONE_PATH/#\~/$${HOME}}" -DEPTH="${DEPTH}" -RECURSE_SUBMODULES="${RECURSE_SUBMODULES}" -CLONE_JOBS="${CLONE_JOBS}" +EXTRA_ARGS_B64="${EXTRA_ARGS}" POST_CLONE_SCRIPT="${POST_CLONE_SCRIPT}" PRE_CLONE_SCRIPT="${PRE_CLONE_SCRIPT}" @@ -50,14 +48,10 @@ fi # Build optional git clone flags CLONE_FLAGS=() -if [ "$DEPTH" -gt 0 ]; then - CLONE_FLAGS+=(--depth "$DEPTH") -fi -if [ "$RECURSE_SUBMODULES" = "true" ]; then - CLONE_FLAGS+=(--recurse-submodules) -fi -if [ "$CLONE_JOBS" -gt 0 ]; then - CLONE_FLAGS+=(--jobs "$CLONE_JOBS") +if [ -n "$EXTRA_ARGS_B64" ]; then + while IFS= read -r arg || [ -n "$arg" ]; do + [ -n "$arg" ] && CLONE_FLAGS+=("$arg") + done < <(echo "$EXTRA_ARGS_B64" | base64 -d) fi # Check if the directory is empty