Supersedes #551 (fork branch couldn't be rebased due to GitHub App permission limitations). Original author: @willshu ## Description Adds support for specifying a git branch when cloning dotfiles repositories. ### Changes - Introduces `dotfiles_branch` and `default_dotfiles_branch` Terraform variables - Adds a `coder_parameter` for `dotfiles_branch` when not explicitly set (with `order` matching `dotfiles_uri`) - Conditionally passes the `--branch` flag to `coder dotfiles` only when branch is non-empty - Adds validation to prevent empty string for `dotfiles_branch` (use `null` to prompt the user) - Default branch is empty string — defers to the repo's default branch rather than assuming `main`, matching the behavior of `coder dotfiles --branch` which states: *"If empty, will default to cloning the default branch or using the existing branch in the cloned repo on disk."* - Adds test coverage for custom branch setting and parameter creation ### Review feedback addressed (from Copilot on #551) - Added `order` field to `dotfiles_branch` parameter for UI consistency with `dotfiles_uri` - Conditional echo message — only shows branch info when set - `--branch` flag only passed when `DOTFILES_BRANCH` is non-empty (both current-user and sudo paths) - Added validation block on `var.dotfiles_branch` to reject empty strings ## Type of Change - [x] Feature/enhancement ## Module Information **Path:** `registry/coder/modules/dotfiles` ## Testing & Validation - [ ] Tests pass (`bun test`) - [ ] Code formatted (`bun fmt`) - [ ] Changes tested locally Co-authored-by: William Shu <william.shu@kkr.com> Co-authored-by: DevCats <christofer@coder.com>
179 lines
5.8 KiB
HCL
179 lines
5.8 KiB
HCL
terraform {
|
|
required_version = ">= 1.0"
|
|
|
|
required_providers {
|
|
coder = {
|
|
source = "coder/coder"
|
|
version = ">= 2.5"
|
|
}
|
|
}
|
|
}
|
|
|
|
variable "order" {
|
|
type = number
|
|
description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
|
|
default = null
|
|
}
|
|
|
|
variable "group" {
|
|
type = string
|
|
description = "The name of a group that this app belongs to."
|
|
default = null
|
|
}
|
|
|
|
variable "agent_id" {
|
|
type = string
|
|
description = "The ID of a Coder agent."
|
|
}
|
|
|
|
variable "description" {
|
|
type = string
|
|
description = "A custom description for the dotfiles parameter. This is shown in the UI - and allows you to customize the instructions you give to your users."
|
|
default = "Enter a URL for a [dotfiles repository](https://dotfiles.github.io) to personalize your workspace. Use an SSH URL (e.g. `git@host:user/repo`) if your Git provider restricts HTTPS cloning."
|
|
}
|
|
|
|
variable "default_dotfiles_uri" {
|
|
type = string
|
|
description = "The default dotfiles URI if the workspace user does not provide one"
|
|
default = ""
|
|
|
|
validation {
|
|
condition = (
|
|
var.default_dotfiles_uri == "" ||
|
|
can(regex("^(https?://|ssh://|git@|git://)[a-zA-Z0-9._/:@~-]+$", var.default_dotfiles_uri))
|
|
)
|
|
error_message = "Must be a valid dotfiles repository URL (https, git@, or git://) without special characters."
|
|
}
|
|
}
|
|
|
|
variable "default_dotfiles_branch" {
|
|
type = string
|
|
description = "The default dotfiles branch if the workspace user does not provide one"
|
|
default = ""
|
|
}
|
|
|
|
variable "dotfiles_uri" {
|
|
type = string
|
|
description = "The URL to a dotfiles repository. (optional, when set, the user isn't prompted for their dotfiles)"
|
|
default = null
|
|
|
|
validation {
|
|
condition = (
|
|
var.dotfiles_uri == null ||
|
|
var.dotfiles_uri == "" ||
|
|
can(regex("^(https?://|ssh://|git@|git://)[a-zA-Z0-9._/:@~-]+$", var.dotfiles_uri))
|
|
)
|
|
error_message = "Must be a valid dotfiles repository URL (https, git@, or git://) without special characters."
|
|
}
|
|
}
|
|
|
|
variable "dotfiles_branch" {
|
|
type = string
|
|
description = "The branch to use for the dotfiles repository (optional, when set, the user isn't prompted for the branch)"
|
|
default = null
|
|
|
|
validation {
|
|
condition = var.dotfiles_branch == null || var.dotfiles_branch != ""
|
|
error_message = "dotfiles_branch cannot be an empty string. Use null to prompt the user or provide a valid branch name."
|
|
}
|
|
}
|
|
|
|
variable "user" {
|
|
type = string
|
|
description = "The name of the user to apply the dotfiles to. (optional, applies to the current user by default)"
|
|
default = null
|
|
|
|
validation {
|
|
condition = var.user == null || can(regex("^[a-zA-Z_][a-zA-Z0-9_-]*$", var.user))
|
|
error_message = "Must be a valid username without special characters."
|
|
}
|
|
}
|
|
|
|
variable "coder_parameter_order" {
|
|
type = number
|
|
description = "The order determines the position of a template parameter in the UI/CLI presentation. The lowest order is shown first and parameters with equal order are sorted by name (ascending order)."
|
|
default = null
|
|
}
|
|
|
|
variable "manual_update" {
|
|
type = bool
|
|
description = "If true, this adds a button to workspace page to refresh dotfiles on demand."
|
|
default = false
|
|
}
|
|
|
|
variable "post_clone_script" {
|
|
description = "Custom script to run after applying dotfiles. Runs every time, even if dotfiles were already applied."
|
|
type = string
|
|
default = null
|
|
}
|
|
|
|
data "coder_parameter" "dotfiles_uri" {
|
|
count = var.dotfiles_uri == null ? 1 : 0
|
|
type = "string"
|
|
name = "dotfiles_uri"
|
|
display_name = "Dotfiles URL"
|
|
order = var.coder_parameter_order
|
|
default = var.default_dotfiles_uri
|
|
description = var.description
|
|
mutable = true
|
|
icon = "/icon/dotfiles.svg"
|
|
|
|
validation {
|
|
regex = "^$|^(https?://|ssh://|git@|git://)[a-zA-Z0-9._/:@~-]+$"
|
|
error = "Must be a valid dotfiles repository URL (https, git@, or git://) without special characters."
|
|
}
|
|
}
|
|
|
|
data "coder_parameter" "dotfiles_branch" {
|
|
count = var.dotfiles_branch == null ? 1 : 0
|
|
type = "string"
|
|
name = "dotfiles_branch"
|
|
display_name = "Dotfiles Branch"
|
|
order = var.coder_parameter_order
|
|
default = var.default_dotfiles_branch
|
|
description = "The branch to use for the dotfiles repository"
|
|
mutable = true
|
|
icon = "/icon/dotfiles.svg"
|
|
}
|
|
|
|
locals {
|
|
dotfiles_uri = var.dotfiles_uri != null ? var.dotfiles_uri : data.coder_parameter.dotfiles_uri[0].value
|
|
dotfiles_branch = var.dotfiles_branch != null ? var.dotfiles_branch : data.coder_parameter.dotfiles_branch[0].value
|
|
user = var.user != null ? var.user : ""
|
|
encoded_post_clone_script = var.post_clone_script != null ? base64encode(var.post_clone_script) : ""
|
|
}
|
|
|
|
resource "coder_script" "dotfiles" {
|
|
agent_id = var.agent_id
|
|
script = templatefile("${path.module}/run.sh", {
|
|
DOTFILES_URI : local.dotfiles_uri,
|
|
DOTFILES_USER : local.user,
|
|
DOTFILES_BRANCH : local.dotfiles_branch,
|
|
POST_CLONE_SCRIPT : local.encoded_post_clone_script
|
|
})
|
|
display_name = "Dotfiles"
|
|
icon = "/icon/dotfiles.svg"
|
|
run_on_start = true
|
|
}
|
|
|
|
resource "coder_app" "dotfiles" {
|
|
count = var.manual_update ? 1 : 0
|
|
agent_id = var.agent_id
|
|
display_name = "Refresh Dotfiles"
|
|
slug = "dotfiles"
|
|
icon = "/icon/dotfiles.svg"
|
|
order = var.order
|
|
group = var.group
|
|
command = templatefile("${path.module}/run.sh", {
|
|
DOTFILES_URI : local.dotfiles_uri,
|
|
DOTFILES_USER : local.user,
|
|
DOTFILES_BRANCH : local.dotfiles_branch,
|
|
POST_CLONE_SCRIPT : local.encoded_post_clone_script
|
|
})
|
|
}
|
|
|
|
output "dotfiles_uri" {
|
|
description = "Dotfiles URI"
|
|
value = local.dotfiles_uri
|
|
}
|