mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add Quickstart template with language and IDE selection (#24904)
Add a new Quickstart starter template that lets users pick programming languages, editors, and an optional Git repo to clone. The template uses Docker under the hood but presents a developer-focused experience: pick your tools, start coding. ## What's included - **Languages parameter** (multi-select): Python, Node.js, Go, Rust, Java, C/C++ - **IDEs parameter** (multi-select): VS Code (Browser), VS Code Desktop, Cursor, JetBrains, Zed, Windsurf - **Git repo parameter**: Optional URL to clone on workspace start - **JetBrains filtering**: Maps selected languages to relevant IDE codes (Python → PyCharm, Go → GoLand, etc.) - **Docker precondition check**: Uses `data "external"` + `terraform_data` precondition to surface a friendly error when Docker is unavailable, before the Docker provider fails with a cryptic message - **4 presets**: Web Development, Backend (Go), Data Science, Full Stack - **Single install script**: All languages install in one `coder_script` to avoid apt-get lock conflicts (agent scripts run in parallel via `errgroup`) <details><summary>Design decisions</summary> - **Docker as invisible backend**: Docker is required on the Coder server but never mentioned in the user-facing parameter UI. The experience is entirely "pick languages, pick editors, start coding." - **`coder_script` over startup_script**: Language installs use a templated script file (`install-languages.sh.tftpl`) driven by the languages parameter. A single script avoids dpkg lock contention since `coder_script` resources execute concurrently. - **`data "external"` for Docker check**: The external provider probes Docker availability independently of the Docker provider. If Docker is down, the `terraform_data` precondition fails with a human-readable message before any `docker_*` resource is evaluated. This depends on the Docker provider connecting lazily (at resource eval time, not at provider init), which current behavior confirms. - **JetBrains filtering by language**: Rather than showing all 9 JetBrains IDEs, the template computes relevant IDE codes from the language selection (e.g. Python → PY, Go → GO) and passes them as `default` to the JetBrains module. - **Arch-aware Go install**: The install script detects `uname -m` to download the correct Go binary for amd64 or arm64. </details> <details><summary>Screenshots and recordings from the UI</summary> <p> <img width="1851" height="1471" alt="Screenshot 2026-05-05 at 2 14 20 PM" src="https://github.com/user-attachments/assets/d4c9cdc5-d311-43a5-9e2e-f90b0019eda7" /> <img width="1851" height="1471" alt="Screenshot 2026-05-05 at 2 15 06 PM" src="https://github.com/user-attachments/assets/cf3023fe-b6db-4503-a6c4-eaa0ec0659f8" /> https://github.com/user-attachments/assets/7507fd7d-ddb5-457a-9f7d-cbf89b36eb20 </p> </details> > [!NOTE] > This PR was authored by Coder Agents.
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ USAGE:
|
||||
Get started with a templated template.
|
||||
|
||||
OPTIONS:
|
||||
--id aws-devcontainer|aws-linux|aws-windows|azure-linux|digitalocean-linux|docker|docker-devcontainer|docker-envbuilder|gcp-devcontainer|gcp-linux|gcp-vm-container|gcp-windows|incus|kubernetes|kubernetes-devcontainer|nomad-docker|scratch|tasks-docker
|
||||
--id aws-devcontainer|aws-linux|aws-windows|azure-linux|digitalocean-linux|docker|docker-devcontainer|docker-envbuilder|gcp-devcontainer|gcp-linux|gcp-vm-container|gcp-windows|incus|kubernetes|kubernetes-devcontainer|nomad-docker|quickstart|scratch|tasks-docker
|
||||
Specify a given example template by ID.
|
||||
|
||||
———
|
||||
|
||||
Generated
+3
-3
@@ -13,8 +13,8 @@ coder templates init [flags] [directory]
|
||||
|
||||
### --id
|
||||
|
||||
| | |
|
||||
|------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Type | <code>aws-devcontainer\|aws-linux\|aws-windows\|azure-linux\|digitalocean-linux\|docker\|docker-devcontainer\|docker-envbuilder\|gcp-devcontainer\|gcp-linux\|gcp-vm-container\|gcp-windows\|incus\|kubernetes\|kubernetes-devcontainer\|nomad-docker\|scratch\|tasks-docker</code> |
|
||||
| | |
|
||||
|------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Type | <code>aws-devcontainer\|aws-linux\|aws-windows\|azure-linux\|digitalocean-linux\|docker\|docker-devcontainer\|docker-envbuilder\|gcp-devcontainer\|gcp-linux\|gcp-vm-container\|gcp-windows\|incus\|kubernetes\|kubernetes-devcontainer\|nomad-docker\|quickstart\|scratch\|tasks-docker</code> |
|
||||
|
||||
Specify a given example template by ID.
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
|
||||
Follow this guide to get your first Coder development environment
|
||||
running in under 10 minutes. This guide covers the essential concepts and shows
|
||||
you how to create your first workspace and run VS Code from it.
|
||||
you how to create your first workspace and open it in your preferred editor.
|
||||
This workspace includes a basic set of tools to edit most code bases.
|
||||
|
||||
## What You'll Do
|
||||
## What you'll do
|
||||
|
||||
In this quickstart, you'll:
|
||||
|
||||
- ✅ Install Coder server
|
||||
- ✅ Create a **template** (blueprint for dev environments)
|
||||
- ✅ Launch a **workspace** (your actual dev environment)
|
||||
- ✅ Connect from your favorite IDE
|
||||
- ✅ Install Coder server.
|
||||
- ✅ Create a **template** (blueprint for dev environments).
|
||||
- ✅ Launch a **workspace** (your actual dev environment).
|
||||
- ✅ Connect from your favorite IDE.
|
||||
|
||||
## Understanding Coder: 30-Second Overview
|
||||
## A 30-second metaphor for Coder
|
||||
|
||||
Before diving in, the following table breaks down the core concepts that power Coder,
|
||||
explained through a cooking analogy:
|
||||
@@ -33,7 +34,7 @@ explained through a cooking analogy:
|
||||
- Familiarity with running commands in the terminal
|
||||
- 10 minutes of your time
|
||||
|
||||
## Step 1: Install Docker and Set Up Permissions
|
||||
## Step 1: Install Docker and set up permissions
|
||||
|
||||
<div class="tabs">
|
||||
|
||||
@@ -92,7 +93,7 @@ is installed.
|
||||
|
||||
</div>
|
||||
|
||||
## Step 2: Install & Start Coder
|
||||
## Step 2: Install and start Coder
|
||||
|
||||
Install the `coder` CLI to get started:
|
||||
|
||||
@@ -149,7 +150,7 @@ viewing the page, locate the web UI URL in Coder logs in your terminal. It looks
|
||||
like `https://<CUSTOM-STRING>.<TUNNEL>.try.coder.app`. It's one of the first
|
||||
lines of output, so you might have to scroll up to find it.
|
||||
|
||||
## Step 3: Initial Setup
|
||||
## Step 3: Initial setup
|
||||
|
||||
1. Create your admin account:
|
||||
- Email: `your.email@example.com`
|
||||
@@ -160,61 +161,67 @@ lines of output, so you might have to scroll up to find it.
|
||||
|
||||

|
||||
|
||||
## Step 4: Create your First Template and Workspace
|
||||
## Step 4: Create your first template and workspace
|
||||
|
||||
> [!TIP]
|
||||
> If you use an AI coding assistant, the [coder-templates](https://github.com/coder/registry/blob/main/.agents/skills/coder-templates/SKILL.md) agent skill can guide you through creating and customizing templates with best practices built-in.
|
||||
|
||||
Templates define what's in your development environment. Let's start simple:
|
||||
Templates define what's in your development environment. The following is a basic example:
|
||||
|
||||
1. Click **"Templates"** → **"New Template"**
|
||||
1. Select **Templates** → **New Template**.
|
||||
|
||||
1. Choose a starter template:
|
||||
2. Select the **Coder Quickstart** template from the list of starter templates.
|
||||
|
||||
| Starter | Best For | Includes |
|
||||
|-------------------------------------|---------------------------------------------------------|--------------------------------------------------------|
|
||||
| **Docker Containers** (Recommended) | Getting started quickly, local development, prototyping | Ubuntu container with common dev tools, Docker runtime |
|
||||
| **Kubernetes (Deployment)** | Cloud-native teams, scalable workspaces | Pod-based workspaces, Kubernetes orchestration |
|
||||
| **AWS EC2 (Linux)** | Teams needing full VMs, AWS-native infrastructure | Full EC2 instances with AWS integration |
|
||||
**Note:** running this template requires Docker to be running in the background, so make sure Docker is running!
|
||||
|
||||
1. Click **"Use template"** on **Docker Containers**. **Note:** running this template requires Docker to be running in the background, so make sure Docker is running!
|
||||
|
||||
1. Name your template:
|
||||
3. Name your template:
|
||||
- Name: `quickstart`
|
||||
- Display name: `quickstart doc template`
|
||||
- Description: `Provision Docker containers as Coder workspaces`
|
||||
|
||||
1. Click **"Save"**
|
||||
4. Select **Save**.
|
||||
|
||||

|
||||
|
||||
**What just happened?** You defined a template — a reusable blueprint for dev
|
||||
environments — in your Coder deployment. It's now stored in your organization's
|
||||
template list, where you and any teammates in the same org can create workspaces
|
||||
from it. Let's launch one.
|
||||
from it. Now it's time launch a workspace.
|
||||
|
||||
## Step 5: Launch your Workspace
|
||||
## Step 5: Launch your workspace
|
||||
|
||||
1. After the template is ready, select **Create Workspace**.
|
||||
1. After the template is ready, select **+ Create Workspace**.
|
||||
|
||||
1. Give the workspace a name and select **Create Workspace**.
|
||||
2. Give the workspace a name. If you need a suggestion for a workspace, you can select the automatically generated name next to the **Need a suggestion?** label.
|
||||
|
||||
1. Coder starts your new workspace:
|
||||
3. In this window are [parameters](../admin/templates/extending-templates/parameters.md) that customize the workspace's behavior. Set the following based on your needs:
|
||||
|
||||
_Workspace
|
||||
is running_
|
||||
- **Programming Languages**: the languages to pre-install in your workspace. You can use more than one if you want.
|
||||
- **IDEs & Editors**: the IDEs and editors you want to configure for quick access once the workspace is running. You can choose more than one if you want.
|
||||
- **Git Repository (Optional)**: the Git repository you want to clone into your workspace. Leave this field blank to skip it.
|
||||
|
||||
**Note:** If you use any of the JetBrains IDEs as your preferred IDE (such as PyCharm, GoLand, or RustRover), select **JetBrains IDEs** as the value. A new parameter will appear, with which you can choose your preferred JetBrains IDE.
|
||||
|
||||
4. Launch your workspace by selecting **Create workspace**.
|
||||
|
||||
After a short wait (10-15 seconds on most modern computers), Coder will start your new workspace:
|
||||
|
||||
_Workspace is running_
|
||||
|
||||
## Step 6: Connect your IDE
|
||||
|
||||
Select **VS Code Desktop** to install the Coder extension and connect to your
|
||||
Coder workspace.
|
||||
Each of the buttons in the workspace view is a different **agent app**
|
||||
(more on this in a later section). Select your preferred IDE from the
|
||||
list of agent apps. This guide assumes you'll use Visual Studio Code,
|
||||
but the process is similar for other IDEs and editors.
|
||||
|
||||
After VS Code loads the remote environment, you can select **Open Folder** to
|
||||
explore directories in the Docker container or work on something new.
|
||||
|
||||

|
||||
|
||||
To clone an existing repository:
|
||||
If you didn't clone an existing Git repository when you created your
|
||||
workspace, you can clone it manually if you want:
|
||||
|
||||
1. Select **Clone Repository** and enter the repository URL.
|
||||
|
||||
@@ -224,25 +231,25 @@ To clone an existing repository:
|
||||
Learn more about how to find the repository URL in the
|
||||
[GitHub documentation](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository).
|
||||
|
||||
1. Choose the folder to which VS Code should clone the repo. It will be in its
|
||||
2. Choose the folder to which VS Code should clone the repo. It will be in its
|
||||
own directory within this folder.
|
||||
|
||||
Note that you cannot create a new parent directory in this step.
|
||||
|
||||
1. After VS Code completes the clone, select **Open** to open the directory.
|
||||
3. After VS Code completes the clone, select **Open** to open the directory.
|
||||
|
||||
1. You are now using VS Code in your Coder environment!
|
||||
4. You are now using VS Code in your Coder environment!
|
||||
|
||||
## Success! You're Coding in Coder
|
||||
## Success! You're coding in Coder
|
||||
|
||||
You now have:
|
||||
|
||||
- **Coder server** running locally
|
||||
- **A template** defining your environment
|
||||
- **A workspace** running that environment
|
||||
- **IDE access** to code remotely
|
||||
- A Coder server running locally.
|
||||
- A template defining your environment.
|
||||
- A workspace running that environment.
|
||||
- IDE access to code remotely.
|
||||
|
||||
### What's Next?
|
||||
### What's next?
|
||||
|
||||
Now that you have your own workspace running, you can start exploring more
|
||||
advanced capabilities that Coder offers.
|
||||
|
||||
@@ -210,6 +210,18 @@
|
||||
],
|
||||
"markdown": "\n# Remote Development on Nomad\n\nProvision Nomad Jobs as [Coder workspaces](https://coder.com/docs/workspaces) with this example template. This example shows how to use Nomad service tasks to be used as a development environment using docker and host csi volumes.\n\n\u003c!-- TODO: Add screenshot --\u003e\n\n\u003e **Note**\n\u003e This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.\n\n## Prerequisites\n\n- [Nomad](https://www.nomadproject.io/downloads)\n- [Docker](https://docs.docker.com/get-docker/)\n\n## Setup\n\n### 1. Start the CSI Host Volume Plugin\n\nThe CSI Host Volume plugin is used to mount host volumes into Nomad tasks. This is useful for development environments where you want to mount persistent volumes into your container workspace.\n\n1. Login to the Nomad server using SSH.\n\n2. Append the following stanza to your Nomad server configuration file and restart the nomad service.\n\n ```tf\n plugin \"docker\" {\n config {\n allow_privileged = true\n }\n }\n ```\n\n ```shell\n sudo systemctl restart nomad\n ```\n\n3. Create a file `hostpath.nomad` with following content:\n\n ```tf\n job \"hostpath-csi-plugin\" {\n datacenters = [\"dc1\"]\n type = \"system\"\n\n group \"csi\" {\n task \"plugin\" {\n driver = \"docker\"\n\n config {\n image = \"registry.k8s.io/sig-storage/hostpathplugin:v1.10.0\"\n\n args = [\n \"--drivername=csi-hostpath\",\n \"--v=5\",\n \"--endpoint=${CSI_ENDPOINT}\",\n \"--nodeid=node-${NOMAD_ALLOC_INDEX}\",\n ]\n\n privileged = true\n }\n\n csi_plugin {\n id = \"hostpath\"\n type = \"monolith\"\n mount_dir = \"/csi\"\n }\n\n resources {\n cpu = 256\n memory = 128\n }\n }\n }\n }\n ```\n\n4. Run the job:\n\n ```shell\n nomad job run hostpath.nomad\n ```\n\n### 2. Setup the Nomad Template\n\n1. Create the template by running the following command:\n\n ```shell\n coder template init nomad-docker\n cd nomad-docker\n coder template push\n ```\n\n2. Set up Nomad server address and optional authentication:\n\n3. Create a new workspace and start developing.\n"
|
||||
},
|
||||
{
|
||||
"id": "quickstart",
|
||||
"url": "",
|
||||
"name": "Coder Quickstart",
|
||||
"description": "Get started with Coder by picking your languages, editors, and a repo",
|
||||
"icon": "/icon/coder.svg",
|
||||
"tags": [
|
||||
"docker",
|
||||
"quickstart"
|
||||
],
|
||||
"markdown": "\n# Coder Quickstart\n\nGet up and running with Coder in minutes. Choose your programming languages, pick your preferred editors, optionally clone a Git repository, and start coding.\n\n## How It Works\n\nWhen you create a workspace from this template, you select:\n\n1. **Languages** to pre-install (Python, Node.js, Go, Rust, Java, C/C++)\n2. **Editors** to connect (VS Code in the browser, VS Code Desktop, Cursor, JetBrains, Zed, Windsurf)\n3. **A Git repository** to clone (optional)\n\nCoder provisions a workspace with your selections and you can start developing immediately.\n\n## Prerequisites\n\nThe host running Coder must have a Docker daemon accessible to the `coder` user:\n\n```sh\n# Add coder user to Docker group\nsudo adduser coder docker\n\n# Restart Coder server\nsudo systemctl restart coder\n\n# Verify access\nsudo -u coder docker ps\n```\n\n## Architecture\n\nThis template provisions:\n\n- **Docker container** (ephemeral) running Ubuntu with the Coder agent\n- **Docker volume** (persistent) mounted at `/home/coder`\n\nFiles in your home directory persist across workspace restarts. Selected languages are installed on first start and cached for subsequent starts.\n\n## Presets\n\nSelect a preset to auto-fill languages and editors for common workflows:\n\n| Preset | Languages | Editors |\n|---------------------|---------------------|-------------------------------------|\n| **Web Development** | Python, Node.js | VS Code (Browser) |\n| **Backend (Go)** | Go | VS Code (Browser), JetBrains GoLand |\n| **Data Science** | Python | VS Code (Browser) |\n| **Full Stack** | Python, Node.js, Go | VS Code (Browser), Cursor |\n\n## IDE Notes\n\n- **VS Code (Browser)**: Opens directly in your browser with no local install required.\n- **VS Code Desktop, Cursor, Windsurf**: Require the desktop application installed on your local machine. Coder opens them via protocol handler.\n- **JetBrains IDEs**: Filtered by your language selection (e.g. PyCharm for Python, GoLand for Go). Requires JetBrains Toolbox or Gateway on your local machine.\n- **Zed**: Connects over SSH. Requires Zed installed on your local machine.\n"
|
||||
},
|
||||
{
|
||||
"id": "scratch",
|
||||
"url": "",
|
||||
|
||||
@@ -40,6 +40,7 @@ var (
|
||||
//go:embed templates/kubernetes
|
||||
//go:embed templates/kubernetes-devcontainer
|
||||
//go:embed templates/nomad-docker
|
||||
//go:embed templates/quickstart
|
||||
//go:embed templates/scratch
|
||||
//go:embed templates/tasks-docker
|
||||
files embed.FS
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
display_name: Coder Quickstart
|
||||
description: Get started with Coder by picking your languages, editors, and a repo
|
||||
icon: ../../../site/static/icon/coder.svg
|
||||
maintainer_github: coder
|
||||
verified: true
|
||||
tags: [docker, quickstart]
|
||||
---
|
||||
|
||||
# Coder Quickstart
|
||||
|
||||
Get up and running with Coder in minutes. Choose your programming languages, pick your preferred editors, optionally clone a Git repository, and start coding.
|
||||
|
||||
## How It Works
|
||||
|
||||
When you create a workspace from this template, you select:
|
||||
|
||||
1. **Languages** to pre-install (Python, Node.js, Go, Rust, Java, C/C++)
|
||||
2. **Editors** to connect (VS Code in the browser, VS Code Desktop, Cursor, JetBrains, Zed, Windsurf)
|
||||
3. **A Git repository** to clone (optional)
|
||||
|
||||
Coder provisions a workspace with your selections and you can start developing immediately.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The host running Coder must have a Docker daemon accessible to the `coder` user:
|
||||
|
||||
```sh
|
||||
# Add coder user to Docker group
|
||||
sudo adduser coder docker
|
||||
|
||||
# Restart Coder server
|
||||
sudo systemctl restart coder
|
||||
|
||||
# Verify access
|
||||
sudo -u coder docker ps
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
This template provisions:
|
||||
|
||||
- **Docker container** (ephemeral) running Ubuntu with the Coder agent
|
||||
- **Docker volume** (persistent) mounted at `/home/coder`
|
||||
|
||||
Files in your home directory persist across workspace restarts. Selected languages are installed on first start and cached for subsequent starts.
|
||||
|
||||
## Presets
|
||||
|
||||
Select a preset to auto-fill languages and editors for common workflows:
|
||||
|
||||
| Preset | Languages | Editors |
|
||||
|---------------------|---------------------|-------------------------------------|
|
||||
| **Web Development** | Python, Node.js | VS Code (Browser) |
|
||||
| **Backend (Go)** | Go | VS Code (Browser), JetBrains GoLand |
|
||||
| **Data Science** | Python | VS Code (Browser) |
|
||||
| **Full Stack** | Python, Node.js, Go | VS Code (Browser), Cursor |
|
||||
|
||||
## IDE Notes
|
||||
|
||||
- **VS Code (Browser)**: Opens directly in your browser with no local install required.
|
||||
- **VS Code Desktop, Cursor, Windsurf**: Require the desktop application installed on your local machine. Coder opens them via protocol handler.
|
||||
- **JetBrains IDEs**: Filtered by your language selection (e.g. PyCharm for Python, GoLand for Go). Requires JetBrains Toolbox or Gateway on your local machine.
|
||||
- **Zed**: Connects over SSH. Requires Zed installed on your local machine.
|
||||
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
LANGUAGES="${LANGUAGES}"
|
||||
APT_UPDATED=false
|
||||
|
||||
apt_update() {
|
||||
if [ "$APT_UPDATED" = "false" ]; then
|
||||
sudo apt-get update -qq
|
||||
APT_UPDATED=true
|
||||
fi
|
||||
}
|
||||
|
||||
if echo "$LANGUAGES" | grep -q "python"; then
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
echo "Python: $(python3 --version)"
|
||||
else
|
||||
echo "Installing Python..."
|
||||
apt_update
|
||||
sudo apt-get install -y -qq python3 python3-pip python3-venv
|
||||
echo "Installed Python: $(python3 --version)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$LANGUAGES" | grep -q "nodejs"; then
|
||||
if command -v node >/dev/null 2>&1; then
|
||||
echo "Node.js: $(node --version)"
|
||||
else
|
||||
echo "Installing Node.js 22..."
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
||||
sudo apt-get install -y -qq nodejs
|
||||
echo "Installed Node.js: $(node --version)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$LANGUAGES" | grep -q "go"; then
|
||||
if command -v /usr/local/go/bin/go >/dev/null 2>&1; then
|
||||
echo "Go: $(/usr/local/go/bin/go version)"
|
||||
else
|
||||
echo "Installing Go..."
|
||||
ARCH=$(uname -m)
|
||||
case $ARCH in
|
||||
x86_64) GOARCH="amd64" ;;
|
||||
aarch64) GOARCH="arm64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
|
||||
esac
|
||||
GO_VERSION=$(curl -fsSL "https://go.dev/VERSION?m=text" | head -1)
|
||||
curl -fsSL "https://go.dev/dl/$${GO_VERSION}.linux-$${GOARCH}.tar.gz" | sudo tar -C /usr/local -xz
|
||||
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' | sudo tee /etc/profile.d/go.sh >/dev/null
|
||||
echo "Installed Go: $(/usr/local/go/bin/go version)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$LANGUAGES" | grep -q "rust"; then
|
||||
if command -v rustc >/dev/null 2>&1 || [ -f "$HOME/.cargo/bin/rustc" ]; then
|
||||
RUSTC=$${HOME}/.cargo/bin/rustc
|
||||
command -v rustc >/dev/null 2>&1 && RUSTC=rustc
|
||||
echo "Rust: $($RUSTC --version)"
|
||||
else
|
||||
echo "Installing Rust..."
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
echo "Installed Rust: $($HOME/.cargo/bin/rustc --version)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$LANGUAGES" | grep -q "java"; then
|
||||
if command -v java >/dev/null 2>&1; then
|
||||
echo "Java: $(java --version 2>&1 | head -1)"
|
||||
else
|
||||
echo "Installing Java (OpenJDK 21)..."
|
||||
apt_update
|
||||
sudo apt-get install -y -qq openjdk-21-jdk
|
||||
echo "Installed Java: $(java --version 2>&1 | head -1)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$LANGUAGES" | grep -q "cpp"; then
|
||||
if command -v gcc >/dev/null 2>&1; then
|
||||
echo "C/C++: $(gcc --version | head -1)"
|
||||
else
|
||||
echo "Installing C/C++ toolchain..."
|
||||
apt_update
|
||||
sudo apt-get install -y -qq gcc g++ make cmake
|
||||
echo "Installed C/C++: $(gcc --version | head -1)"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Language setup complete."
|
||||
@@ -0,0 +1,450 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
external = {
|
||||
source = "hashicorp/external"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
# --- Parameters ---
|
||||
|
||||
data "coder_parameter" "languages" {
|
||||
name = "languages"
|
||||
display_name = "Programming Languages"
|
||||
description = "Select the languages to pre-install in your workspace"
|
||||
type = "list(string)"
|
||||
form_type = "multi-select"
|
||||
default = jsonencode(["python"])
|
||||
mutable = true
|
||||
icon = "/icon/code.svg"
|
||||
order = 1
|
||||
|
||||
option {
|
||||
name = "Python"
|
||||
value = "python"
|
||||
icon = "/icon/python.svg"
|
||||
}
|
||||
option {
|
||||
name = "Node.js"
|
||||
value = "nodejs"
|
||||
icon = "/icon/nodejs.svg"
|
||||
}
|
||||
option {
|
||||
name = "Go"
|
||||
value = "go"
|
||||
icon = "/icon/go.svg"
|
||||
}
|
||||
option {
|
||||
name = "Rust"
|
||||
value = "rust"
|
||||
icon = "/icon/rust.svg"
|
||||
}
|
||||
option {
|
||||
name = "Java"
|
||||
value = "java"
|
||||
icon = "/icon/java.svg"
|
||||
}
|
||||
option {
|
||||
name = "C/C++"
|
||||
value = "cpp"
|
||||
icon = "/icon/cpp.svg"
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "ides" {
|
||||
name = "ides"
|
||||
display_name = "IDEs & Editors"
|
||||
description = "Select the development environments for your workspace"
|
||||
type = "list(string)"
|
||||
form_type = "multi-select"
|
||||
default = jsonencode(["code-server"])
|
||||
mutable = true
|
||||
icon = "/icon/code.svg"
|
||||
order = 2
|
||||
|
||||
option {
|
||||
name = "VS Code (Browser)"
|
||||
value = "code-server"
|
||||
icon = "/icon/code.svg"
|
||||
}
|
||||
option {
|
||||
name = "VS Code Desktop"
|
||||
value = "vscode-desktop"
|
||||
icon = "/icon/code.svg"
|
||||
}
|
||||
option {
|
||||
name = "Cursor"
|
||||
value = "cursor"
|
||||
icon = "/icon/cursor.svg"
|
||||
}
|
||||
option {
|
||||
name = "JetBrains IDEs"
|
||||
value = "jetbrains"
|
||||
icon = "/icon/jetbrains.svg"
|
||||
}
|
||||
option {
|
||||
name = "Zed"
|
||||
value = "zed"
|
||||
icon = "/icon/zed.svg"
|
||||
}
|
||||
option {
|
||||
name = "Windsurf"
|
||||
value = "windsurf"
|
||||
icon = "/icon/windsurf.svg"
|
||||
}
|
||||
}
|
||||
|
||||
# Shown only when "JetBrains IDEs" is selected in the IDEs parameter.
|
||||
# Pre-selects IDEs that match the chosen languages.
|
||||
data "coder_parameter" "jetbrains_ides" {
|
||||
count = contains(local.ides, "jetbrains") ? 1 : 0
|
||||
name = "jetbrains_ides"
|
||||
display_name = "JetBrains IDEs"
|
||||
description = "Select the JetBrains IDEs to install"
|
||||
type = "list(string)"
|
||||
form_type = "multi-select"
|
||||
default = jsonencode(local.jetbrains_ides_from_languages)
|
||||
mutable = true
|
||||
icon = "/icon/jetbrains.svg"
|
||||
order = 3
|
||||
|
||||
option {
|
||||
name = "IntelliJ IDEA"
|
||||
value = "IU"
|
||||
icon = "/icon/intellij.svg"
|
||||
}
|
||||
option {
|
||||
name = "PyCharm"
|
||||
value = "PY"
|
||||
icon = "/icon/pycharm.svg"
|
||||
}
|
||||
option {
|
||||
name = "GoLand"
|
||||
value = "GO"
|
||||
icon = "/icon/goland.svg"
|
||||
}
|
||||
option {
|
||||
name = "WebStorm"
|
||||
value = "WS"
|
||||
icon = "/icon/webstorm.svg"
|
||||
}
|
||||
option {
|
||||
name = "RustRover"
|
||||
value = "RR"
|
||||
icon = "/icon/rustrover.svg"
|
||||
}
|
||||
option {
|
||||
name = "CLion"
|
||||
value = "CL"
|
||||
icon = "/icon/clion.svg"
|
||||
}
|
||||
option {
|
||||
name = "PhpStorm"
|
||||
value = "PS"
|
||||
icon = "/icon/phpstorm.svg"
|
||||
}
|
||||
option {
|
||||
name = "RubyMine"
|
||||
value = "RM"
|
||||
icon = "/icon/rubymine.svg"
|
||||
}
|
||||
option {
|
||||
name = "Rider"
|
||||
value = "RD"
|
||||
icon = "/icon/rider.svg"
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "git_repo" {
|
||||
name = "git_repo"
|
||||
display_name = "Git Repository (Optional)"
|
||||
description = "URL of a Git repository to clone into your workspace (leave empty to skip)"
|
||||
type = "string"
|
||||
default = ""
|
||||
mutable = true
|
||||
icon = "/icon/git.svg"
|
||||
order = 4
|
||||
}
|
||||
|
||||
# --- Locals ---
|
||||
|
||||
locals {
|
||||
username = data.coder_workspace_owner.me.name
|
||||
languages = jsondecode(data.coder_parameter.languages.value)
|
||||
ides = jsondecode(data.coder_parameter.ides.value)
|
||||
|
||||
# Map selected languages to the relevant JetBrains IDE product codes.
|
||||
# Used as the default for the JetBrains IDE selector parameter.
|
||||
jetbrains_by_language = {
|
||||
python = ["PY"]
|
||||
go = ["GO"]
|
||||
java = ["IU"]
|
||||
nodejs = ["WS"]
|
||||
rust = ["RR"]
|
||||
cpp = ["CL"]
|
||||
}
|
||||
jetbrains_ides_from_languages = distinct(flatten([
|
||||
for lang in local.languages : lookup(local.jetbrains_by_language, lang, [])
|
||||
]))
|
||||
|
||||
# The actual JetBrains IDEs to install, from the user's selection
|
||||
# in the conditional JetBrains parameter (or empty if not shown).
|
||||
jetbrains_selected = contains(local.ides, "jetbrains") ? jsondecode(data.coder_parameter.jetbrains_ides[0].value) : []
|
||||
}
|
||||
|
||||
# --- Agent ---
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
EOT
|
||||
|
||||
env = {
|
||||
GIT_AUTHOR_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
|
||||
GIT_AUTHOR_EMAIL = "${data.coder_workspace_owner.me.email}"
|
||||
GIT_COMMITTER_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
|
||||
GIT_COMMITTER_EMAIL = "${data.coder_workspace_owner.me.email}"
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# --- Language installation ---
|
||||
# All languages install in a single script to avoid apt-get lock
|
||||
# conflicts (coder_script resources run in parallel).
|
||||
|
||||
resource "coder_script" "install_languages" {
|
||||
count = length(local.languages) > 0 ? 1 : 0
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install Languages"
|
||||
icon = "/icon/code.svg"
|
||||
run_on_start = true
|
||||
start_blocks_login = true
|
||||
script = templatefile("${path.module}/install-languages.sh.tftpl", {
|
||||
LANGUAGES = join(",", local.languages)
|
||||
})
|
||||
}
|
||||
|
||||
# --- IDE modules ---
|
||||
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count * (contains(local.ides, "code-server") ? 1 : 0)
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
order = 1
|
||||
}
|
||||
|
||||
module "vscode-desktop" {
|
||||
count = data.coder_workspace.me.start_count * (contains(local.ides, "vscode-desktop") ? 1 : 0)
|
||||
source = "registry.coder.com/coder/vscode-desktop/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder"
|
||||
order = 2
|
||||
}
|
||||
|
||||
module "cursor" {
|
||||
count = data.coder_workspace.me.start_count * (contains(local.ides, "cursor") ? 1 : 0)
|
||||
source = "registry.coder.com/coder/cursor/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder"
|
||||
order = 3
|
||||
}
|
||||
|
||||
# TODO: Re-add the coder/jetbrains module once Coder's dynamic
|
||||
# parameter system respects module count for parameter visibility.
|
||||
# The module's internal coder_parameter appears even when count = 0,
|
||||
# creating a ghost parameter in the workspace creation form.
|
||||
# module "jetbrains" {
|
||||
# count = data.coder_workspace.me.start_count * (contains(local.ides, "jetbrains") && length(local.jetbrains_selected) > 0 ? 1 : 0)
|
||||
# source = "registry.coder.com/coder/jetbrains/coder"
|
||||
# version = "~> 1.0"
|
||||
# agent_id = coder_agent.main.id
|
||||
# folder = "/home/coder"
|
||||
# default = toset(local.jetbrains_selected)
|
||||
# }
|
||||
|
||||
module "zed" {
|
||||
count = data.coder_workspace.me.start_count * (contains(local.ides, "zed") ? 1 : 0)
|
||||
source = "registry.coder.com/coder/zed/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder"
|
||||
order = 5
|
||||
}
|
||||
|
||||
module "windsurf" {
|
||||
count = data.coder_workspace.me.start_count * (contains(local.ides, "windsurf") ? 1 : 0)
|
||||
source = "registry.coder.com/coder/windsurf/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder"
|
||||
order = 6
|
||||
}
|
||||
|
||||
# --- Git clone ---
|
||||
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count * (data.coder_parameter.git_repo.value != "" ? 1 : 0)
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
url = data.coder_parameter.git_repo.value
|
||||
}
|
||||
|
||||
# --- Presets ---
|
||||
|
||||
data "coder_workspace_preset" "web_dev" {
|
||||
name = "Web Development"
|
||||
icon = "/icon/nodejs.svg"
|
||||
parameters = {
|
||||
languages = jsonencode(["python", "nodejs"])
|
||||
ides = jsonencode(["code-server"])
|
||||
git_repo = ""
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_workspace_preset" "backend_go" {
|
||||
name = "Backend (Go)"
|
||||
icon = "/icon/go.svg"
|
||||
parameters = {
|
||||
languages = jsonencode(["go"])
|
||||
ides = jsonencode(["code-server", "jetbrains"])
|
||||
jetbrains_ides = jsonencode(["GO"])
|
||||
git_repo = ""
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_workspace_preset" "data_science" {
|
||||
name = "Data Science"
|
||||
icon = "/icon/python.svg"
|
||||
parameters = {
|
||||
languages = jsonencode(["python"])
|
||||
ides = jsonencode(["code-server"])
|
||||
git_repo = ""
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_workspace_preset" "full_stack" {
|
||||
name = "Full Stack"
|
||||
icon = "/icon/code.svg"
|
||||
parameters = {
|
||||
languages = jsonencode(["python", "nodejs", "go"])
|
||||
ides = jsonencode(["code-server", "cursor"])
|
||||
git_repo = ""
|
||||
}
|
||||
}
|
||||
|
||||
# --- Docker resources ---
|
||||
|
||||
resource "docker_volume" "home_volume" {
|
||||
name = "coder-${data.coder_workspace.me.id}-home"
|
||||
lifecycle {
|
||||
ignore_changes = all
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_name_at_creation"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
depends_on = []
|
||||
}
|
||||
|
||||
resource "docker_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
hostname = data.coder_workspace.me.name
|
||||
entrypoint = [
|
||||
"sh", "-c",
|
||||
replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
|
||||
]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_name"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
depends_on = []
|
||||
}
|
||||
@@ -22,9 +22,9 @@ const selectTags = (starterTemplatesByTag: StarterTemplatesByTag) => {
|
||||
};
|
||||
|
||||
const sortVisibleTemplates = (templates: TemplateExample[]) => {
|
||||
// The docker template should be first, as it's the easiest way to get
|
||||
// started with Coder.
|
||||
const featuredTemplateIds = ["docker"];
|
||||
// The quickstart template should be first, as it's the easiest
|
||||
// way to get started with Coder.
|
||||
const featuredTemplateIds = ["quickstart", "docker"];
|
||||
|
||||
const featuredTemplates: TemplateExample[] = [];
|
||||
for (const id of featuredTemplateIds) {
|
||||
|
||||
@@ -10,12 +10,12 @@ import { docs } from "#/utils/docs";
|
||||
|
||||
// Those are from https://github.com/coder/coder/tree/main/examples/templates
|
||||
const featuredExampleIds = [
|
||||
"quickstart",
|
||||
"docker",
|
||||
"kubernetes",
|
||||
"aws-linux",
|
||||
"aws-windows",
|
||||
"gcp-linux",
|
||||
"gcp-windows",
|
||||
"azure-linux",
|
||||
];
|
||||
|
||||
const findFeaturedExamples = (examples: TemplateExample[]) => {
|
||||
|
||||
Reference in New Issue
Block a user