diff --git a/.icons/personalize.svg b/.icons/personalize.svg index 778808d..31a9ad8 100644 --- a/.icons/personalize.svg +++ b/.icons/personalize.svg @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/.images/aws-regions.png b/.images/aws-regions.png new file mode 100644 index 0000000..4a79efe Binary files /dev/null and b/.images/aws-regions.png differ diff --git a/.images/gcp-regions.png b/.images/gcp-regions.png new file mode 100644 index 0000000..1e0c362 Binary files /dev/null and b/.images/gcp-regions.png differ diff --git a/.images/jetbrains-gateway.png b/.images/jetbrains-gateway.png new file mode 100644 index 0000000..75807f6 Binary files /dev/null and b/.images/jetbrains-gateway.png differ diff --git a/.images/jupyterlab.webp b/.images/jupyterlab.webp new file mode 100644 index 0000000..d87f7c0 Binary files /dev/null and b/.images/jupyterlab.webp differ diff --git a/.images/vscode-server.gif b/.images/vscode-server.gif new file mode 100644 index 0000000..dcc563c Binary files /dev/null and b/.images/vscode-server.gif differ diff --git a/.sample/README.md b/.sample/README.md new file mode 100644 index 0000000..ebc3e49 --- /dev/null +++ b/.sample/README.md @@ -0,0 +1,65 @@ +--- +display_name: MODULE_NAME +description: Describe what this module does +icon: ../.icons/.svg +maintainer_github: GITHUB_USERNAME +verified: false +tags: [helper] +--- + +# MODULE_NAME + + + + + +```hcl +module "MODULE_NAME" { + source = "https://registry.coder.com/modules/MODULE_NAME" +} +``` + +## Examples + +### Example 1 + +Install the Dracula theme from [OpenVSX](https://open-vsx.org/): + +```hcl +module "MODULE_NAME" { + source = "https://registry.coder.com/modules/MODULE_NAME" + agent_id = coder_agent.example.id + extensions = [ + "dracula-theme.theme-dracula" + ] +} +``` + +Enter the `.` into the extensions array and code-server will automatically install on start. + +### Example 2 + +Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) file: + +```hcl +module "MODULE_NAME" { + source = "https://registry.coder.com/modules/MODULE_NAME" + agent_id = coder_agent.example.id + extensions = [ "dracula-theme.theme-dracula" ] + settings = { + "workbench.colorTheme" = "Dracula" + } +} +``` + +### Example 3 + +Run code-server in the background, don't fetch it from GitHub: + +```hcl +module "MODULE_NAME" { + source = "https://registry.coder.com/modules/MODULE_NAME" + agent_id = coder_agent.example.id + offline = true +} +``` diff --git a/.sample/main.tf b/.sample/main.tf new file mode 100644 index 0000000..5dcaf01 --- /dev/null +++ b/.sample/main.tf @@ -0,0 +1,101 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.12" + } + } +} + +locals { + # A built-in icon like "/icon/code.svg" or a full URL of icon + icon_url = "https://raw.githubusercontent.com/coder/coder/main/site/static/icon/code.svg" + # a map of all possible values + options = { + "Option 1" = { + "name" = "Option 1", + "value" = "1" + "icon" = "/emojis/1.png" + } + "Option 2" = { + "name" = "Option 2", + "value" = "2" + "icon" = "/emojis/2.png" + } + } +} + +# Add required variables for your modules and remove any unneeded variables +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "log_path" { + type = string + description = "The path to log MODULE_NAME to." + default = "/tmp/MODULE_NAME.log" +} + +variable "port" { + type = number + description = "The port to run MODULE_NAME on." + default = 19999 +} + +variable "mutable" { + type = bool + description = "Whether the parameter is mutable." + default = true +} +# Add other variables here + + +resource "coder_script" "MODULE_NAME" { + agent_id = var.agent_id + display_name = "MODULE_NAME" + icon = local.icon_url + script = templatefile("${path.module}/run.sh", { + LOG_PATH : var.log_path, + }) + run_on_start = true + run_on_stopt = false +} + +resource "coder_app" "MODULE_NAME" { + agent_id = var.agent_id + slug = "MODULE_NAME" + display_name = "MODULE_NAME" + url = "http://localhost:${var.port}" + icon = loocal.icon_url + subdomain = false + share = "owner" + + # Remove if the app does not have a healthcheck endpoint + healthcheck { + url = "http://localhost:${var.port}/healthz" + interval = 5 + threshold = 6 + } +} + +data "coder_parameter" "MODULE_NAME" { + type = "list(string)" + name = "MODULE_NAME" + display_name = "MODULE_NAME" + icon = local.icon_url + mutable = var.mutable + default = local.options["Option 1"]["value"] + + dynamic "option" { + for_each = local.options + content { + icon = option.value.icon + name = option.value.name + value = option.value.value + } + } +} + diff --git a/.sample/run.sh b/.sample/run.sh new file mode 100755 index 0000000..88af7ad --- /dev/null +++ b/.sample/run.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env sh + +echo "Instalalting ${MODULE_NAME}..." +# Add code here +# Use varibles from the templatefile function in main.tf +# e.g. LOG_PATH, PORT, etc. + +echo "Installation comlete!" + +echo "Starting ${MODULE_NAME}..." +# Start the app in here +# 1. Use & to run it in background +# 2. redirct stdout and stderr to log files + +./app >${LOG_PATH} 2>&1 & + +echo "Sample app started!" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..eb8d484 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing + +To create a new module, clone this repository and run: + +```shell +./new.sh MOUDLE_NAME +``` + +Test a module by running an instance of Coder on your local machine: + +```shell +coder server --in-memory +``` + +This will create a new module in the modules directory with the given name and scaffolding. +Edit the files, adding your module's implementation, documentation and screenshots. + +## Testing a Module + +Create a template and edit it to include your development module: + +> [!NOTE] +> The Docker starter template is recommended for quick-iteration! + +```hcl +module "MOUDLE_NAME" { + source = "/home/user/coder/modules/MOUDLE_NAME" +} +``` + +You can also test your module by specifying the source as a git repository: + +```hcl +module "MOUDLE_NAME" { + source = "git::https://github.com//.git//?ref=" +} +``` + +Build a workspace and your module will be consumed! 🥳 + +Open a pull-request with your module, a member of the Coder team will +manually test it, and after-merge it will appear on the Registry. diff --git a/README.md b/README.md index 308a45e..b01b24d 100644 --- a/README.md +++ b/README.md @@ -32,30 +32,4 @@ Check out the [Coder Registry](https://registry.coder.com) for instructions to i ## Contributing a Module -To quickly start contributing with a new module, clone this repository and run: - -```sh -./new.sh -``` - -Test a module by running an instance of Coder on your local machine: - -```bash -coder server --in-memory -``` - -Create a template and edit it to include your development module: - -> *Info* -> The Docker starter template is recommended for quick-iteration! - -```tf -module "testing" { - source = "/home/user/coder/modules/my-new-module" -} -``` - -Build a workspace and your module will be consumed! 🥳 - -Open a pull-request with your module, a member of the Coder team will -manually test it, and after-merge it will appear on the Registry. +See [CONTRIBUTING.md](./CONTRIBUTING.md) for instructions on how to construct and publish a module to the [Coder Registry](https://registry.coder.com). diff --git a/aws-region/README.md b/aws-region/README.md index ecd27ac..1051cc6 100644 --- a/aws-region/README.md +++ b/aws-region/README.md @@ -4,7 +4,7 @@ description: A parameter with human region names and icons icon: ../.icons/aws.svg maintainer_github: coder verified: true -tags: [helper, parameter] +tags: [helper, parameter, regions, aws] --- # AWS Region @@ -12,6 +12,8 @@ tags: [helper, parameter] A parameter with all AWS regions. This allows developers to select the region closest to them. +![AWS Regions](../.images/aws-region.png) + ## Examples ### Default Region diff --git a/azure-region/README.md b/azure-region/README.md index e630933..cb14303 100644 --- a/azure-region/README.md +++ b/azure-region/README.md @@ -4,7 +4,7 @@ description: A parameter with human region names and icons icon: ../.icons/azure.svg maintainer_github: coder verified: true -tags: [helper, parameter, azure] +tags: [helper, parameter, azure, regions] --- # Azure Region @@ -59,4 +59,4 @@ module "azure-region" { resource "azurerm_resource_group" "example" { location = module.azure_region.value } -``` \ No newline at end of file +``` diff --git a/code-server/README.md b/code-server/README.md index 6f068ed..9f360e1 100644 --- a/code-server/README.md +++ b/code-server/README.md @@ -4,7 +4,7 @@ description: VS Code in the browser icon: ../.icons/code.svg maintainer_github: coder verified: true -tags: [helper, ide] +tags: [helper, ide, web] --- # code-server @@ -63,4 +63,4 @@ module "settings" { agent_id = coder_agent.example.id offline = true } -``` \ No newline at end of file +``` diff --git a/gcp-region/README.md b/gcp-region/README.md index 9407845..553a8fd 100644 --- a/gcp-region/README.md +++ b/gcp-region/README.md @@ -1,32 +1,47 @@ --- -display_name: GCP Regions +display_name: GCP Region description: Add Google Cloud Platform regions to your Coder template. icon: ../.icons/gcp.svg maintainer_github: coder verified: true -tags: [gcp, regions, zones, helper] +tags: [gcp, regions, parameter, helper] --- # Google Cloud Platform Regions This module adds Google Cloud Platform regions to your Coder template. +![GCP Regions](../.images/gcp-regions.png) + ## Examples 1. Add only GPU zones in the US West 1 region: ```hcl - module "regions" { - source = "https://registry.coder.com/modules/gcp-regions" - default = ["us-west1"] - gpu_only = true + module "gcp_region" { + source = "https://registry.coder.com/modules/gcp-region" + default = ["us-west1-a"] + regions = ["us-west1"] + gpu_only = false } ``` 2. Add all zones in the Europe West region: ```hcl - module "regions" { - source = "https://registry.coder.com/modules/gcp-regions" - default = ["europe-west"] + module "gcp_region" { + source = "https://registry.coder.com/modules/gcp-region" + regions = ["europe-west"] + single_zone_per_region = false + } + ``` + +3. Add a single zone from each region in US and Europe that laos has GPUs + + ```hcl + module "gcp_region" { + source = "https://registry.coder.com/modules/gcp-region" + regions = ["us", "europe"] + gpu_only = true + single_zone_per_region = true } ``` diff --git a/gcp-region/main.tf b/gcp-region/main.tf index 1114466..4d675c8 100644 --- a/gcp-region/main.tf +++ b/gcp-region/main.tf @@ -22,6 +22,12 @@ variable "description" { } variable "default" { + default = null + description = "Default zone" + type = string +} + +variable "regions" { description = "List of GCP regions to include." type = list(string) default = ["us-central1"] @@ -51,6 +57,12 @@ variable "custom_icons" { type = map(string) } +variable "single_zone_per_region" { + default = true + description = "Whether to only include a single zone per region." + type = bool +} + locals { zones = { # US Central @@ -343,17 +355,17 @@ locals { "europe-west2-a" = { gpu = true name = "London, England (a)" - icon = "/emojis/1f173-1f1ff.png" + icon = "/emojis/1f1ec-1f1e7.png" } "europe-west2-b" = { gpu = true name = "London, England (b)" - icon = "/emojis/1f173-1f1ff.png" + icon = "/emojis/1f1ec-1f1e7.png" } "europe-west2-c" = { gpu = false name = "London, England (c)" - icon = "/emojis/1f173-1f1ff.png" + icon = "/emojis/1f1ec-1f1e7.png" } "europe-west3-b" = { @@ -702,14 +714,16 @@ data "coder_parameter" "region" { description = var.description icon = "/icon/gcp.png" mutable = var.mutable + default = var.default != null && var.default != "" ? var.default : null dynamic "option" { for_each = { for k, v in local.zones : k => v - if anytrue([for d in var.default : startswith(k, d)]) && (!var.gpu_only || v.gpu) + if anytrue([for d in var.regions : startswith(k, d)]) && (!var.gpu_only || v.gpu) && (!var.single_zone_per_region || endswith(k, "-a")) } content { - icon = try(var.custom_icons[option.key], option.value.icon) - name = try(var.custom_names[option.key], option.value.name) + icon = try(var.custom_icons[option.key], option.value.icon) + # if single_zone_per_region is true, remove the zone letter from the name + name = try(var.custom_names[option.key], var.single_zone_per_region ? substr(option.value.name, 0, length(option.value.name) - 4) : option.value.name) description = option.key value = option.key } @@ -717,5 +731,11 @@ data "coder_parameter" "region" { } output "value" { - value = data.coder_parameter.region.value + description = "GCP zone identifier." + value = data.coder_parameter.region.value +} + +output "region" { + description = "GCP region identifier." + value = substr(data.coder_parameter.region.value, 0, length(data.coder_parameter.region.value) - 2) } diff --git a/jetbrains-gateway/README.md b/jetbrains-gateway/README.md index 3b67d22..7abe4d2 100644 --- a/jetbrains-gateway/README.md +++ b/jetbrains-gateway/README.md @@ -4,29 +4,32 @@ description: Add a one-click button to launch JetBrains Gateway IDEs in the dash icon: ../.icons/gateway.svg maintainer_github: coder verified: true -tags: [ide, jetbrains, gateway, goland, webstorm, intellij, pycharm, phpstorm, clion, rubymine, datagrip, rider] +tags: [ide, jetbrains, helper, parameter] --- # JetBrains Gateway -This module adds a JetBrains Gateway IDEs to your Coder template. +This module adds a JetBrains Gateway Button to open any workspace with a single click. -## How to use this module +![JetBrains Gateway IDes list](../.images/jetbrains-gateway.png) -To use this module, add the following snippet to your template manifest: +## Examples + +### Add GoLand and WebStorm with the default set to GoLand ```hcl module "jetbrains_gateway" { source = "https://registry.coder.com/modules/jetbrains-gateway" - agent_id = coder_agent.main.id - agent_name = "main" - project_directory = "/home/coder/project" - gateway_ide_product_code = ["GO","WS"] # A list of JetBrains product codes use ["ALL"] for all products + agent_id = coder_agent.example.id + agent_name = "example" + project_directory = "/home/coder/example" + jetbrains_ides = ["GO", "WS"] + default = "GO" } ``` ## Supported IDEs -The following JetBrains IDEs are supported: +This module and JetBrains Gateway support the following JetBrains IDEs: - GoLand (`GO`) - WebStorm (`WS`) diff --git a/jetbrains-gateway/main.tf b/jetbrains-gateway/main.tf index 993ea41..9e01cf0 100644 --- a/jetbrains-gateway/main.tf +++ b/jetbrains-gateway/main.tf @@ -24,23 +24,26 @@ variable "project_directory" { description = "The directory to open in the IDE. e.g. /home/coder/project" } -variable "gateway_ide_product_code" { +variable "default" { + type = string + description = "Default IDE" +} + +variable "jetbrains_ides" { type = list(string) - description = "The list of IDE product codes, e.g. ['GO', 'WS'] or ['ALL']" - default = ["ALL"] + description = "The list of IDE product codes." validation { condition = ( - length(var.gateway_ide_product_code) == 1 && var.gateway_ide_product_code[0] == "ALL" || alltrue([ - for code in var.gateway_ide_product_code : contains(["IU", "IC", "PS", "WS", "PY", "PC", "CL", "GO", "DB", "RD", "RM"], code) + for code in var.jetbrains_ides : contains(["IU", "IC", "PS", "WS", "PY", "PC", "CL", "GO", "DB", "RD", "RM"], code) ]) ) - error_message = "The gateway_ide_product_code must be ['ALL'] or a list of valid product codes. https://plugins.jetbrains.com/docs/marketplace/product-codes.html" + error_message = "The jetbrains_ides must be a list of valid product codes. https://plugins.jetbrains.com/docs/marketplace/product-codes.html" } } locals { - gateway_ides = { + jetbrains_ides = { "GO" = { icon = "/icon/goland.svg", name = "GoLand", @@ -105,10 +108,10 @@ data "coder_parameter" "jetbrains_ide" { display_name = "JetBrains IDE" icon = "/icon/gateway.svg" mutable = true - default = local.gateway_ides["GO"].value + default = var.default != null && var.default != "" ? local.jetbrains_ides[var.default].value : null dynamic "option" { - for_each = contains(var.gateway_ide_product_code, "ALL") ? local.gateway_ides : { for key, value in local.gateway_ides : key => value if contains(var.gateway_ide_product_code, key) } + for_each = { for key, value in local.jetbrains_ides : key => value if contains(var.jetbrains_ides, key) } content { icon = option.value.icon name = option.value.name @@ -127,3 +130,7 @@ resource "coder_app" "gateway" { icon = data.coder_parameter.jetbrains_ide.option[index(data.coder_parameter.jetbrains_ide.option.*.value, data.coder_parameter.jetbrains_ide.value)].icon external = true } + +output "jetbrains_ides" { + value = data.coder_parameter.jetbrains_ide.value +} diff --git a/jupyterhub/README.md b/jupyterhub/README.md deleted file mode 100644 index ab123ed..0000000 --- a/jupyterhub/README.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -display_name: JupyterHub -description: A multi-user version of the notebook designed for companies, classrooms and research labs -icon: ../.icons/jupyter.svg -maintainer_github: coder -verified: true -tags: [helper, ide] ---- - -# JupyterHub - -Automatically install [JupyterHub](https://jupyter.org/hub) in a workspace, and create an app to access it via the dashboard. - -## Examples - -TODO \ No newline at end of file diff --git a/jupyterlab/README.md b/jupyterlab/README.md new file mode 100644 index 0000000..d551f96 --- /dev/null +++ b/jupyterlab/README.md @@ -0,0 +1,21 @@ +--- +display_name: JupyterLab +description: A module that adds JupyterLab in your Coder template. +icon: ../.icons/jupyter.svg +maintainer_github: coder +verified: true +tags: [jupyter, helper, ide, web] +--- + +# JupyterLab + +A module that adds JupyterLab in your Coder template. + +![JupyterLab](../.images/jupyterlab.webp) + +```hcl +module "jupyterlab" { + source = "https://registry.coder.com/modules/jupyterlab" + agent_id = coder_agent.example.id +} +``` diff --git a/jupyterlab/main.tf b/jupyterlab/main.tf new file mode 100644 index 0000000..e95c0a2 --- /dev/null +++ b/jupyterlab/main.tf @@ -0,0 +1,54 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.12" + } + } +} + +locals { + icon_url = "/icon/jupyter.svg" +} + +# Add required variables for your modules and remove any unneeded variables +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "log_path" { + type = string + description = "The path to log jupyterlab to." + default = "/tmp/jupyterlab.log" +} + +variable "port" { + type = number + description = "The port to run jupyterlab on." + default = 19999 +} + +resource "coder_script" "jupyterlab" { + agent_id = var.agent_id + display_name = "jupyterlab" + icon = local.icon_url + script = templatefile("${path.module}/run.sh", { + LOG_PATH : var.log_path, + PORT : var.port + }) + run_on_start = true + run_on_stopt = false +} + +resource "coder_app" "jupyterlab" { + agent_id = var.agent_id + slug = "jupyterlab" + display_name = "JupyterLab" + url = "http://localhost:${var.port}" + icon = local.icon_url + subdomain = true + share = "owner" +} diff --git a/jupyterlab/run.sh b/jupyterlab/run.sh new file mode 100755 index 0000000..a3a484a --- /dev/null +++ b/jupyterlab/run.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env sh + +echo "Instalalting ${MODULE_NAME}..." + +# check if jupyterlab is installed +if ! command -v jupyterlab &> /dev/null then + # install jupyterlab + # check if python3 pip is installed + if ! command -v pip3 &> /dev/null then + echo "pip3 is not installed" + echo "Please install pip3 and try again" + exit 1 + fi + pip3 install jupyterlab + echo "jupyterlab installed!" +fi + +echo "Starting ${MODULE_NAME}..." + +$HOME/.local/bin/jupyter lab --no-browser --LabApp.token='' --LabApp.password='' >${LOG_PATH} 2>&1 & + +echo "Started ${MODULE_NAME}!" diff --git a/kasmvnc/README.md b/kasmvnc/README.md index 1803268..0bfcaf9 100644 --- a/kasmvnc/README.md +++ b/kasmvnc/README.md @@ -4,7 +4,7 @@ description: A modern open source VNC server icon: ../.icons/kasmvnc.svg maintainer_github: coder verified: true -tags: [helper, ide] +tags: [helper, VNC, web] --- # KasmVNC @@ -13,4 +13,27 @@ Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and ## Examples -TODO \ No newline at end of file +1. Add latest version of KasmVNC with [`lxde`](https://www.lxde.org/) desktop environment: + + ```hcl + module "kasmvnc" { + source = "https://registry.coder.com/modules/kasmvnc" + agent_id = coder_agent.example.id + } + + ``` + +2. Add specific version of KasmVNC with [`mate`](https://mate-desktop.org/) desktop environment and custom port: + + ```hcl + module "kasmvnc" { + source = "https://registry.coder.com/modules/kasmvnc" + agent_id = coder_agent.example.id + version = "1.0.0" + desktop_environment = "mate" + port = 6080 + } + + ``` + +![Screenshot of KasmVNC]() //TODO diff --git a/kasmvnc/main.tf b/kasmvnc/main.tf new file mode 100644 index 0000000..6fd0ba4 --- /dev/null +++ b/kasmvnc/main.tf @@ -0,0 +1,55 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.12" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "port" { + type = number + description = "The port to run KasmVNC on." + default = 8443 +} + +variable "desktop_environment" { + type = string + description = "The desktop environment to for KasmVNC (xfce, lxde, mate, etc)." + default = "lxde" +} + +variable "version" { + type = string + description = "Version of KasmVNC to install." + default = "1.2.0" +} + +resource "coder_script" "kasm_vnc" { + agent_id = var.agent_id + display_name = "KasmVNC" + icon = "/icon/kasmvnc.svg" + script = templatefile("${path.module}/run.sh", { + PORT : var.port, + DESKTOP_ENVIRONMENT : var.desktop_environment, + VERSION : var.version + }) + run_on_start = true +} + +resource "coder_app" "kasm_vnc" { + agent_id = var.agent_id + slug = "kasm-vnc" + display_name = "kasmVNC" + url = "http://localhost:${var.port}" + icon = "/icon/kasmvnc.svg" + subdomain = false + share = "owner" +} diff --git a/kasmvnc/run.sh b/kasmvnc/run.sh new file mode 100644 index 0000000..7a59580 --- /dev/null +++ b/kasmvnc/run.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Check if desktop enivronment is installed +if ! dpkg -s ${DESKTOP_ENVIRONMENT} &>/dev/null; then + sudo apt-get update + DEBIAN_FRONTEND=noninteractive sudo apt-get install -y ${DESKTOP_ENVIRONMENT} +else + echo "${DESKTOP_ENVIRONMENT} is already installed." +fi + +# Check if vncserver is installed +if ! dpkg -s kasmvncserver &>/dev/null; then + cd /tmp + wget https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_focal_${VERSION}_amd64.deb + sudo apt install -y ./kasmvncserver_focal_${VERSION}_amd64.deb + printf "🥳 KasmVNC v${VERSION} has been successfully installed!\n\n" +else + echo "KasmVNC is already installed." +fi + +sudo addgroup $USER ssl-cert + +# Coder port-forwarding from dashboard only supports HTTP +sudo bash -c 'cat > /etc/kasmvnc/kasmvnc.yaml <" + exit 1 +fi + +# Create module directory and exit if it alredy exists +if [ -d "$MODULE_NAME" ]; then + echo "Module with name $MODULE_NAME already exists" + echo "Please choose a different name" + exit 1 +fi +mkdir -p "${MODULE_NAME}" + +# Copy required files from the sample module +cp -r .sample/* "${MODULE_NAME}" + +# Change to module directory +cd "${MODULE_NAME}" + +# Detect OS +if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + sed -i '' "s/MODULE_NAME/${MODULE_NAME}/g" main.tf + sed -i '' "s/MODULE_NAME/${MODULE_NAME}/g" README.md +else + # Linux + sed -i "s/MODULE_NAME/${MODULE_NAME}/g" main.tf + sed -i "s/MODULE_NAME/${MODULE_NAME}/g" README.md +fi + +# Make run.sh executable +chmod +x run.sh diff --git a/vscode-desktop/README.md b/vscode-desktop/README.md index 4ec37a1..c188c45 100644 --- a/vscode-desktop/README.md +++ b/vscode-desktop/README.md @@ -4,6 +4,7 @@ description: Add a one-click button to launch VS Code Desktop icon: ../.icons/code.svg maintainer_github: coder verified: true +tags: [ide, vscode, helper] --- # VS Code Desktop diff --git a/vscode-server/README.md b/vscode-server/README.md new file mode 100644 index 0000000..dfbec39 --- /dev/null +++ b/vscode-server/README.md @@ -0,0 +1,38 @@ +--- +display_name: vscode-server +description: VS Code Web - Visual Studio Code in the browser +icon: ../.icons/code.svg +maintainer_github: coder +verified: true +tags: [helper, ide, vscode, web] +--- + +# VS Code Web + +Automatically install [Visual Studio Code Server](https://code.visualstudio.com/docs/remote/vscode-server) in a workspace using the [VS Code CLIs](https://code.visualstudio.com/docs/editor/command-line) and create an app to access it via the dashboard. + +![VS Code Server with GitHub Copilot and live-share](../.images/vscode-server.gif) + +## Examples + +1. Install VS Code Server with default settings: + + ```hcl + module "vscode-web" { + source = "https://registry.coder.com/modules/vscode-server" + agent_id = coder_agent.example.id + accept_license = true + } + ``` + +2. Install VS Code Server to a custom folder: + + ```hcl + module "vscode-web" { + source = "https://registry.coder.com/modules/vscode-server" + agent_id = coder_agent.example.id + install_dir = "/home/coder/.vscode-server" + folder = "/home/coder" + accept_license = true + } + ``` diff --git a/vscode-server/main.tf b/vscode-server/main.tf new file mode 100644 index 0000000..bd86703 --- /dev/null +++ b/vscode-server/main.tf @@ -0,0 +1,77 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.12" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "port" { + type = number + description = "The port to run VS Code Web on." + default = 13338 +} + +variable "folder" { + type = string + description = "The folder to open in vscode-server." + default = "" +} + +variable "log_path" { + type = string + description = "The path to log." + default = "/tmp/vscode-server.log" +} + +variable "install_dir" { + type = string + description = "The directory to install VS Code CLI" + default = "/tmp/vscode-cli" +} + +variable "accept_license" { + type = bool + description = "Accept the VS Code license. https://code.visualstudio.com/license" + default = false + validation { + condition = var.accept_license == true + error_message = "You must accept the VS Code license agreement by setting accept_license=true." + } +} + +resource "coder_script" "vscode-server" { + agent_id = var.agent_id + display_name = "VS Code Web" + icon = "/icon/code.svg" + script = templatefile("${path.module}/run.sh", { + PORT : var.port, + LOG_PATH : var.log_path, + INSTALL_DIR : var.install_dir, + }) + run_on_start = true +} + +resource "coder_app" "vscode-server" { + agent_id = var.agent_id + slug = "vscode-server" + display_name = "VS Code Web" + url = var.folder == "" ? "http://localhost:${var.port}" : "http://localhost:${var.port}?folder=${var.folder}" + icon = "/icon/code.svg" + subdomain = true + share = "owner" + + healthcheck { + url = "http://localhost:${var.port}/healthz" + interval = 5 + threshold = 6 + } +} diff --git a/vscode-server/run.sh b/vscode-server/run.sh new file mode 100644 index 0000000..ddec273 --- /dev/null +++ b/vscode-server/run.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh + +BOLD='\033[0;1m' + +# Create install directory if it doesn't exist +mkdir -p ${INSTALL_DIR} + +printf "$${BOLD}Installing vscode-cli!\n" + +# Download and extract code-cli tarball +output=$(curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-x64' --output vscode_cli.tar.gz && tar -xf vscode_cli.tar.gz -C ${INSTALL_DIR} && rm vscode_cli.tar.gz) + +if [ $? -ne 0 ]; then + echo "Failed to install vscode-cli: $output" + exit 1 +fi +printf "🥳 vscode-cli has been installed.\n\n" + +echo "👷 Running ${INSTALL_DIR}/bin/code serve-web --port ${PORT} --without-connection-token --accept-server-license-terms in the background..." +echo "Check logs at ${LOG_PATH}!" +${INSTALL_DIR}/code serve-web --port ${PORT} --without-connection-token --accept-server-license-terms >${LOG_PATH} 2>&1 &