Compare commits

..

10 Commits

Author SHA1 Message Date
Muhammad Atif Ali b88d50a7c9
Merge branch 'main' into atif/multi-gateway 7 months ago
Muhammad Atif Ali cd6aa274f1 fix tests 7 months ago
Muhammad Atif Ali 2f51d70fb7 always use latest and update default versions to 2024.3 7 months ago
Muhammad Atif Ali dbf3c47f45
Merge branch 'main' into atif/multi-gateway 7 months ago
Muhammad Atif Ali d45f2e6ad1 Update JetBrains Gateway module to v1.0.24 8 months ago
Muhammad Atif Ali 70020d8b8c Support multiple default IDEs in JetBrains Gateway 8 months ago
Muhammad Atif Ali 937ffcd47b Update slug format for JetBrains Gateway apps
This change improves URL uniqueness by appending a lowercase IDE
identifier to the slug, ensuring distinct slugs for each default IDE.
8 months ago
Muhammad Atif Ali 5bc2aa4aa0 Fix JetBrains Gateway tests for multiple IDEs
- Allow creation of links with multiple IDEs.
- Ensure outputs handle arrays for identifying multiple IDEs.
- Update runTerraformApply to handle array values as JSON strings.
8 months ago
Muhammad Atif Ali 4452630a7e Support multiple default IDEs in JetBrains Gateway 8 months ago
Muhammad Atif Ali 27e3faf31c feat: enable multiple IDE buttons in JetBrains
Add support for specifying a list of default IDEs to be displayed on
the Workspace page. This allows users to see multiple IDE options
simultaneously. Ensure no duplicates are included and validate
provided IDE codes against allowed set. Adjust logic to dynamically
render IDE buttons based on specified defaults, improving flexibility
in user interface setup.
8 months ago

@ -48,7 +48,7 @@ update_component_status() {
# Function to create an incident
create_incident() {
local incident_name="Degraded Service"
local incident_name="Testing Instatus"
local message="The following modules are experiencing issues:\n"
for i in "${!failures[@]}"; do
message+="$((i + 1)). ${failures[$i]}\n"
@ -59,7 +59,7 @@ create_incident() {
component_status="MAJOROUTAGE"
fi
# see https://instatus.com/help/api/incidents
incident_id=$(curl -s -X POST "https://api.instatus.com/v1/$INSTATUS_PAGE_ID/incidents" \
response=$(curl -s -X POST "https://api.instatus.com/v1/$INSTATUS_PAGE_ID/incidents" \
-H "Authorization: Bearer $INSTATUS_API_KEY" \
-H "Content-Type: application/json" \
-d "{
@ -74,25 +74,10 @@ create_incident() {
\"status\": \"PARTIALOUTAGE\"
}
]
}" | jq -r '.id')
}")
echo "Created incident with ID: $incident_id"
}
# Function to check for existing unresolved incidents
check_existing_incident() {
# Fetch the latest incidents with status not equal to "RESOLVED"
local unresolved_incidents=$(curl -s -X GET "https://api.instatus.com/v1/$INSTATUS_PAGE_ID/incidents" \
-H "Authorization: Bearer $INSTATUS_API_KEY" \
-H "Content-Type: application/json" | jq -r '.incidents[] | select(.status != "RESOLVED") | .id')
if [[ -n "$unresolved_incidents" ]]; then
echo "Unresolved incidents found: $unresolved_incidents"
return 0 # Indicate that there are unresolved incidents
else
echo "No unresolved incidents found."
return 1 # Indicate that no unresolved incidents exist
fi
incident_id=$(echo "$response" | jq -r '.id')
echo "$incident_id"
}
force_redeploy_registry () {
@ -189,15 +174,13 @@ else
update_component_status "PARTIALOUTAGE"
fi
# Check if there is an existing incident before creating a new one
if ! check_existing_incident; then
create_incident
fi
# Create a new incident
incident_id=$(create_incident)
echo "Created incident with ID: $incident_id"
# If a module is down, force a reployment to try getting things back online
# ASAP
# EDIT: registry.coder.com is no longer hosted on vercel
#force_redeploy_registry
force_redeploy_registry
fi
exit "${status}"

@ -16,23 +16,14 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Terraform
uses: coder/coder/.github/actions/setup-tf@main
- name: Set up Bun
uses: oven-sh/setup-bun@v2
- uses: actions/checkout@v4
- uses: coder/coder/.github/actions/setup-tf@main
- uses: oven-sh/setup-bun@v2
with:
# We're using the latest version of Bun for now, but it might be worth
# reconsidering. They've pushed breaking changes in patch releases
# that have broken our CI.
# Our PR where issues started to pop up: https://github.com/coder/modules/pull/383
# The Bun PR that broke things: https://github.com/oven-sh/bun/pull/16067
bun-version: latest
- name: Install dependencies
- name: Setup
run: bun install
- name: Run tests
run: bun test
- run: bun test
pretty:
runs-on: ubuntu-latest
steps:

@ -1,37 +0,0 @@
name: deploy-registry
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
# Set id-token permission for gcloud
# Adding a comment because retriggering the build manually hung? I am the lord of devops and you will bend?
permissions:
contents: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935
with:
workload_identity_provider: projects/309789351055/locations/global/workloadIdentityPools/github-actions/providers/github
service_account: registry-v2-github@coder-registry-1.iam.gserviceaccount.com
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a
# For the time being, let's have the first couple merges to main in modules deploy a new version
# to *dev*. Once we review and make sure everything's working, we can deploy a new version to *main*.
# Maybe in the future we could automate this based on the result of E2E tests.
- name: Deploy to dev.registry.coder.com
run: |
gcloud builds triggers run 29818181-126d-4f8a-a937-f228b27d3d34 --branch dev

5
.gitignore vendored

@ -1,7 +1,4 @@
.terraform*
node_modules
*.tfstate
*.tfstate.lock.info
# Ignore generated credentials from google-github-actions/auth
gha-creds-*.json
*.tfstate.lock.info

@ -13,7 +13,6 @@ tags: [helper]
```tf
module "MODULE_NAME" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/MODULE_NAME/coder"
version = "1.0.2"
}
@ -29,7 +28,6 @@ Install the Dracula theme from [OpenVSX](https://open-vsx.org/):
```tf
module "MODULE_NAME" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/MODULE_NAME/coder"
version = "1.0.2"
agent_id = coder_agent.example.id
@ -47,7 +45,6 @@ Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarte
```tf
module "MODULE_NAME" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/MODULE_NAME/coder"
version = "1.0.2"
agent_id = coder_agent.example.id

@ -17,7 +17,6 @@ e.g.
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.2"
agent_id = coder_agent.main.id

@ -14,7 +14,6 @@ A module that adds Apache Airflow in your Coder template.
```tf
module "airflow" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/apache-airflow/coder"
version = "1.0.13"
agent_id = coder_agent.main.id

@ -16,7 +16,6 @@ Customize the preselected parameter value:
```tf
module "aws-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/aws-region/coder"
version = "1.0.12"
default = "us-east-1"
@ -37,7 +36,6 @@ Change the display name and icon for a region using the corresponding maps:
```tf
module "aws-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/aws-region/coder"
version = "1.0.12"
default = "ap-south-1"
@ -64,7 +62,6 @@ Hide the Asia Pacific regions Seoul and Osaka:
```tf
module "aws-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/aws-region/coder"
version = "1.0.12"
exclude = ["ap-northeast-2", "ap-northeast-3"]

@ -13,7 +13,6 @@ This module adds a parameter with all Azure regions, allowing developers to sele
```tf
module "azure_region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/azure-region/coder"
version = "1.0.12"
default = "eastus"
@ -34,7 +33,6 @@ Change the display name and icon for a region using the corresponding maps:
```tf
module "azure-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/azure-region/coder"
version = "1.0.12"
custom_names = {
@ -58,7 +56,6 @@ Hide all regions in Australia except australiacentral:
```tf
module "azure-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/azure-region/coder"
version = "1.0.12"
exclude = [

@ -13,9 +13,8 @@ Automatically install [code-server](https://github.com/coder/code-server) in a w
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
}
```
@ -28,9 +27,8 @@ module "code-server" {
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
install_version = "4.8.3"
}
@ -42,9 +40,8 @@ Install the Dracula theme from [OpenVSX](https://open-vsx.org/):
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
extensions = [
"dracula-theme.theme-dracula"
@ -56,13 +53,12 @@ Enter the `<author>.<name>` into the extensions array and code-server will autom
### Pre-configure Settings
Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settings-json-file) file:
Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) file:
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
extensions = ["dracula-theme.theme-dracula"]
settings = {
@ -77,9 +73,8 @@ Just run code-server in the background, don't fetch it from GitHub:
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
}
@ -93,9 +88,8 @@ Run an existing copy of code-server if found, otherwise download from GitHub:
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
use_cached = true
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
@ -106,9 +100,8 @@ Just run code-server in the background, don't fetch it from GitHub:
```tf
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
offline = true
}

@ -39,7 +39,7 @@ variable "slug" {
}
variable "settings" {
type = any
type = map(string)
description = "A map of settings to apply to code-server."
default = {}
}

@ -104,8 +104,7 @@ if [ "${AUTO_INSTALL_EXTENSIONS}" = true ]; then
if [ -f "$WORKSPACE_DIR/.vscode/extensions.json" ]; then
printf "🧩 Installing extensions from %s/.vscode/extensions.json...\n" "$WORKSPACE_DIR"
# Use sed to remove single-line comments before parsing with jq
extensions=$(sed 's|//.*||g' "$WORKSPACE_DIR"/.vscode/extensions.json | jq -r '.recommendations[]')
extensions=$(jq -r '.recommendations[]' "$WORKSPACE_DIR"/.vscode/extensions.json)
for extension in $extensions; do
if extension_installed "$extension"; then
continue

@ -13,7 +13,6 @@ Automatically logs the user into Coder when creating their workspace.
```tf
module "coder-login" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/coder-login/coder"
version = "1.0.15"
agent_id = coder_agent.example.id

@ -15,7 +15,6 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/cursor-coder)
```tf
module "cursor" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/cursor/coder"
version = "1.0.19"
agent_id = coder_agent.example.id
@ -28,7 +27,6 @@ module "cursor" {
```tf
module "cursor" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/cursor/coder"
version = "1.0.19"
agent_id = coder_agent.example.id

@ -17,9 +17,8 @@ Under the hood, this module uses the [coder dotfiles](https://coder.com/docs/v2/
```tf
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/dotfiles/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
}
```
@ -30,9 +29,8 @@ module "dotfiles" {
```tf
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/dotfiles/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
}
```
@ -41,9 +39,8 @@ module "dotfiles" {
```tf
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/dotfiles/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
user = "root"
}
@ -53,16 +50,14 @@ module "dotfiles" {
```tf
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/dotfiles/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
}
module "dotfiles-root" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/dotfiles/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
user = "root"
dotfiles_uri = module.dotfiles.dotfiles_uri
@ -75,9 +70,8 @@ You can set a default dotfiles repository for all users by setting the `default_
```tf
module "dotfiles" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/dotfiles/coder"
version = "1.0.29"
version = "1.0.18"
agent_id = coder_agent.example.id
default_dotfiles_uri = "https://github.com/coder/dotfiles"
}

@ -1,7 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
DOTFILES_URI="${DOTFILES_URI}"
DOTFILES_USER="${DOTFILES_USER}"

@ -16,7 +16,6 @@ Customize the preselected parameter value:
```tf
module "exoscale-instance-type" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-instance-type/coder"
version = "1.0.12"
default = "standard.medium"
@ -45,7 +44,6 @@ Change the display name a type using the corresponding maps:
```tf
module "exoscale-instance-type" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-instance-type/coder"
version = "1.0.12"
default = "standard.medium"
@ -80,7 +78,6 @@ Show only gpu1 types
```tf
module "exoscale-instance-type" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-instance-type/coder"
version = "1.0.12"
default = "gpu.large"

@ -16,7 +16,6 @@ Customize the preselected parameter value:
```tf
module "exoscale-zone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-zone/coder"
version = "1.0.12"
default = "ch-dk-2"
@ -44,7 +43,6 @@ Change the display name and icon for a zone using the corresponding maps:
```tf
module "exoscale-zone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-zone/coder"
version = "1.0.12"
default = "at-vie-1"

@ -13,9 +13,8 @@ A file browser for your workspace.
```tf
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.23"
agent_id = coder_agent.example.id
}
```
@ -28,9 +27,8 @@ module "filebrowser" {
```tf
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.23"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
@ -40,9 +38,8 @@ module "filebrowser" {
```tf
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.23"
agent_id = coder_agent.example.id
database_path = ".config/filebrowser.db"
}
@ -52,9 +49,7 @@ module "filebrowser" {
```tf
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
agent_id = coder_agent.example.id
agent_name = "main"
subdomain = false

@ -39,7 +39,7 @@ describe("filebrowser", async () => {
"",
"📂 Serving /root at http://localhost:13339 ",
"",
"Running 'filebrowser --noauth --root /root --port 13339 --baseurl ' ",
"Running 'filebrowser --noauth --root /root --port 13339' ",
"",
"📝 Logs at /tmp/filebrowser.log",
]);
@ -61,7 +61,7 @@ describe("filebrowser", async () => {
"",
"📂 Serving /root at http://localhost:13339 ",
"",
"Running 'filebrowser --noauth --root /root --port 13339 -d .config/filebrowser.db --baseurl ' ",
"Running 'filebrowser --noauth --root /root --port 13339 -d .config/filebrowser.db' ",
"",
"📝 Logs at /tmp/filebrowser.log",
]);
@ -75,7 +75,7 @@ describe("filebrowser", async () => {
const output = await executeScriptInContainer(state, "alpine");
expect(output.exitCode).toBe(0);
expect(output.stdout).toEqual([
"\u001b[0;1mInstalling filebrowser ",
"\u001B[0;1mInstalling filebrowser ",
"",
"🥳 Installation complete! ",
"",
@ -83,7 +83,7 @@ describe("filebrowser", async () => {
"",
"📂 Serving /home/coder/project at http://localhost:13339 ",
"",
"Running 'filebrowser --noauth --root /home/coder/project --port 13339 --baseurl ' ",
"Running 'filebrowser --noauth --root /home/coder/project --port 13339' ",
"",
"📝 Logs at /tmp/filebrowser.log",
]);
@ -106,7 +106,7 @@ describe("filebrowser", async () => {
"",
"📂 Serving /root at http://localhost:13339 ",
"",
"Running 'filebrowser --noauth --root /root --port 13339 --baseurl /@default/default.main/apps/filebrowser' ",
"Running 'filebrowser --noauth --root /root --port 13339' ",
"",
"📝 Logs at /tmp/filebrowser.log",
]);

@ -21,10 +21,13 @@ if [ "${DB_PATH}" != "filebrowser.db" ]; then
DB_FLAG=" -d ${DB_PATH}"
fi
# set baseurl to be able to run if sudomain=false; if subdomain=true the SERVER_BASE_PATH value will be ""
filebrowser config set --baseurl "${SERVER_BASE_PATH}"$${DB_FLAG} > ${LOG_PATH} 2>&1
printf "📂 Serving $${ROOT_DIR} at http://localhost:${PORT} \n\n"
printf "Running 'filebrowser --noauth --root $ROOT_DIR --port ${PORT}$${DB_FLAG} --baseurl ${SERVER_BASE_PATH}' \n\n"
printf "Running 'filebrowser --noauth --root $ROOT_DIR --port ${PORT}$${DB_FLAG}' \n\n"
filebrowser --noauth --root $ROOT_DIR --port ${PORT}$${DB_FLAG} --baseurl ${SERVER_BASE_PATH} > ${LOG_PATH} 2>&1 &
filebrowser --noauth --root $ROOT_DIR --port ${PORT}$${DB_FLAG} > ${LOG_PATH} 2>&1 &
printf "📝 Logs at ${LOG_PATH} \n\n"

@ -15,7 +15,6 @@ We can use the simplest format here, only adding a default selection as the `atl
```tf
module "fly-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/fly-region/coder"
version = "1.0.2"
default = "atl"
@ -32,7 +31,6 @@ The regions argument can be used to display only the desired regions in the Code
```tf
module "fly-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/fly-region/coder"
version = "1.0.2"
default = "ams"
@ -48,7 +46,6 @@ Set custom icons and names with their respective maps.
```tf
module "fly-region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/fly-region/coder"
version = "1.0.2"
default = "ams"

@ -13,7 +13,6 @@ This module adds Google Cloud Platform regions to your Coder template.
```tf
module "gcp_region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/gcp-region/coder"
version = "1.0.12"
regions = ["us", "europe"]
@ -34,7 +33,6 @@ Note: setting `gpu_only = true` and using a default region without GPU support,
```tf
module "gcp_region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/gcp-region/coder"
version = "1.0.12"
default = ["us-west1-a"]
@ -51,7 +49,6 @@ resource "google_compute_instance" "example" {
```tf
module "gcp_region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/gcp-region/coder"
version = "1.0.12"
regions = ["europe-west"]
@ -67,7 +64,6 @@ resource "google_compute_instance" "example" {
```tf
module "gcp_region" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/gcp-region/coder"
version = "1.0.12"
regions = ["us", "europe"]

@ -13,7 +13,6 @@ This module allows you to automatically clone a repository by URL and skip if it
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -27,7 +26,6 @@ module "git-clone" {
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -42,7 +40,6 @@ To use with [Git Authentication](https://coder.com/docs/v2/latest/admin/git-prov
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -68,7 +65,6 @@ data "coder_parameter" "git_repo" {
# Clone the repository for branch `feat/example`
module "git_clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -77,24 +73,23 @@ module "git_clone" {
# Create a code-server instance for the cloned repository
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/code-server/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
order = 1
folder = "/home/${local.username}/${module.git_clone[count.index].folder_name}"
folder = "/home/${local.username}/${module.git_clone.folder_name}"
}
# Create a Coder app for the website
resource "coder_app" "website" {
count = data.coder_workspace.me.start_count
agent_id = coder_agent.example.id
order = 2
slug = "website"
external = true
display_name = module.git_clone[count.index].folder_name
url = module.git_clone[count.index].web_url
icon = module.git_clone[count.index].git_provider != "" ? "/icon/${module.git_clone[count.index].git_provider}.svg" : "/icon/git.svg"
display_name = module.git_clone.folder_name
url = module.git_clone.web_url
icon = module.git_clone.git_provider != "" ? "/icon/${module.git_clone.git_provider}.svg" : "/icon/git.svg"
count = module.git_clone.web_url != "" ? 1 : 0
}
```
@ -102,7 +97,6 @@ Configuring `git-clone` for a self-hosted GitHub Enterprise Server running at `g
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -121,7 +115,6 @@ To GitLab clone with a specific branch like `feat/example`
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -133,7 +126,6 @@ Configuring `git-clone` for a self-hosted GitLab running at `gitlab.example.com`
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -154,7 +146,6 @@ For example, to clone the `feat/example` branch:
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id
@ -171,7 +162,6 @@ For example, this will clone into the `~/projects/coder/coder-dev` folder:
```tf
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder"
version = "1.0.18"
agent_id = coder_agent.example.id

@ -9,9 +9,6 @@ tags: [helper, git]
# git-commit-signing
> [!IMPORTANT]
> This module will only work with Git versions >=2.34, prior versions [do not support signing commits via SSH keys](https://lore.kernel.org/git/xmqq8rxpgwki.fsf@gitster.g/).
This module downloads your SSH key from Coder and uses it to sign commits with Git.
It requires `curl` and `jq` to be installed inside your workspace.
@ -21,7 +18,6 @@ This module has a chance of conflicting with the user's dotfiles / the personali
```tf
module "git-commit-signing" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-commit-signing/coder"
version = "1.0.11"
agent_id = coder_agent.example.id

@ -13,7 +13,6 @@ Runs a script that updates git credentials in the workspace to match the user's
```tf
module "git-config" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-config/coder"
version = "1.0.15"
agent_id = coder_agent.example.id
@ -28,7 +27,6 @@ TODO: Add screenshot
```tf
module "git-config" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-config/coder"
version = "1.0.15"
agent_id = coder_agent.example.id
@ -42,7 +40,6 @@ TODO: Add screenshot
```tf
module "git-config" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-config/coder"
version = "1.0.15"
agent_id = coder_agent.example.id

@ -13,7 +13,6 @@ Templates that utilize Github External Auth can automatically ensure that the Co
```tf
module "github-upload-public-key" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/github-upload-public-key/coder"
version = "1.0.15"
agent_id = coder_agent.example.id
@ -46,7 +45,6 @@ data "coder_external_auth" "github" {
}
module "github-upload-public-key" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/github-upload-public-key/coder"
version = "1.0.15"
agent_id = coder_agent.example.id

@ -11,18 +11,15 @@ tags: [ide, jetbrains, helper, parameter]
This module adds a JetBrains Gateway Button to open any workspace with a single click.
JetBrains recommends a minimum of 4 CPU cores and 8GB of RAM.
Consult the [JetBrains documentation](https://www.jetbrains.com/help/idea/prerequisites.html#min_requirements) to confirm other system requirements.
```tf
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.28"
version = "1.0.24"
agent_id = coder_agent.example.id
agent_name = "example"
folder = "/home/coder/example"
jetbrains_ides = ["CL", "GO", "IU", "PY", "WS"]
default = "GO"
default = ["GO"]
}
```
@ -34,53 +31,28 @@ module "jetbrains_gateway" {
```tf
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.28"
version = "1.0.24"
agent_id = coder_agent.example.id
agent_name = "example"
folder = "/home/coder/example"
jetbrains_ides = ["GO", "WS"]
default = "GO"
default = ["GO"]
}
```
### Use the latest version of each IDE
### Use the fixed version
```tf
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.28"
version = "1.0.24"
agent_id = coder_agent.example.id
agent_name = "example"
folder = "/home/coder/example"
jetbrains_ides = ["IU", "PY"]
default = "IU"
latest = true
}
```
### Use fixed versions set by `jetbrains_ide_versions`
```tf
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.28"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["IU", "PY"]
default = "IU"
latest = false
jetbrains_ide_versions = {
"IU" = {
build_number = "243.21565.193"
version = "2024.3"
}
"PY" = {
build_number = "243.21565.199"
version = "2024.3"
}
}
jetbrains_ides = ["GO", "WS"]
default = ["GO"]
latest = false # current version is 2024.3
}
```
@ -88,13 +60,13 @@ module "jetbrains_gateway" {
```tf
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.28"
version = "1.0.24"
agent_id = coder_agent.example.id
agent_name = "example"
folder = "/home/coder/example"
jetbrains_ides = ["GO", "WS"]
default = "GO"
default = ["GO"]
latest = true
channel = "eap"
}
@ -106,15 +78,30 @@ Due to the highest priority of the `ide_download_link` parameter in the `(jetbra
```tf
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.28"
version = "1.0.24"
agent_id = coder_agent.example.id
agent_name = "example"
folder = "/home/coder/example"
jetbrains_ides = ["GO", "WS"]
releases_base_link = "https://releases.internal.site/"
download_base_link = "https://download.internal.site/"
default = "GO"
default = ["GO"]
}
```
### Add multiple IDEs
**Note:** This removes the choice of IDE from the user.
```tf
module "jetbrains_gateway" {
source = "registry.coder.com/modules/jetbrains-gateway/coder"
version = "1.0.24"
agent_id = coder_agent.example.id
agent_name = "example"
folder = "/home/coder/example"
default = ["GO", "WS"]
}
```
@ -122,12 +109,11 @@ module "jetbrains_gateway" {
This module and JetBrains Gateway support the following JetBrains IDEs:
- [GoLand (`GO`)](https://www.jetbrains.com/go/)
- [WebStorm (`WS`)](https://www.jetbrains.com/webstorm/)
- [IntelliJ IDEA Ultimate (`IU`)](https://www.jetbrains.com/idea/)
- [PyCharm Professional (`PY`)](https://www.jetbrains.com/pycharm/)
- [PhpStorm (`PS`)](https://www.jetbrains.com/phpstorm/)
- [CLion (`CL`)](https://www.jetbrains.com/clion/)
- [RubyMine (`RM`)](https://www.jetbrains.com/ruby/)
- [Rider (`RD`)](https://www.jetbrains.com/rider/)
- [RustRover (`RR`)](https://www.jetbrains.com/rust/)
- GoLand (`GO`)
- WebStorm (`WS`)
- IntelliJ IDEA Ultimate (`IU`)
- PyCharm Professional (`PY`)
- PhpStorm (`PS`)
- CLion (`CL`)
- RubyMine (`RM`)
- Rider (`RD`)

@ -10,18 +10,19 @@ describe("jetbrains-gateway", async () => {
await testRequiredVariables(import.meta.dir, {
agent_id: "foo",
agent_name: "foo",
folder: "/home/foo",
});
it("should create a link with the default values", async () => {
const state = await runTerraformApply(import.meta.dir, {
// These are all required.
agent_id: "foo",
agent_name: "foo",
folder: "/home/coder",
});
expect(state.outputs.url.value).toBe(
"jetbrains-gateway://connect#type=coder&workspace=default&owner=default&folder=/home/coder&url=https://mydeployment.coder.com&token=$SESSION_TOKEN&ide_product_code=IU&ide_build_number=243.21565.193&ide_download_link=https://download.jetbrains.com/idea/ideaIU-2024.3.tar.gz",
);
expect(state.outputs.url.value).toEqual([
"jetbrains-gateway://connect#type=coder&workspace=default&owner=default&agent=foo&folder=/home/coder&url=https://mydeployment.coder.com&token=$SESSION_TOKEN&ide_product_code=IU&ide_build_number=243.21565.193&ide_download_link=https://download.jetbrains.com/idea/ideaIU-2024.3.tar.gz",
]);
const coder_app = state.resources.find(
(res) => res.type === "coder_app" && res.name === "gateway",
@ -32,12 +33,31 @@ describe("jetbrains-gateway", async () => {
expect(coder_app?.instances[0].attributes.order).toBeNull();
});
it("default to first ide", async () => {
it("default to first IDE", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
agent_name: "foo",
folder: "/home/foo",
jetbrains_ides: ["IU", "PY"],
});
expect(state.outputs.identifier.value).toEqual(["IU"]);
expect(state.outputs.url.value).toEqual([
"jetbrains-gateway://connect#type=coder&workspace=default&owner=default&agent=foo&folder=/home/foo&url=https://mydeployment.coder.com&token=$SESSION_TOKEN&ide_product_code=IU&ide_build_number=243.21565.193&ide_download_link=https://download.jetbrains.com/idea/ideaIU-2024.3.tar.gz",
]);
});
it("should create multiple IDEs", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
agent_name: "foo",
folder: "/home/foo",
jetbrains_ides: '["IU", "GO", "PY"]',
default: ["GO", "IU", "PY"],
});
expect(state.outputs.identifier.value).toBe("IU");
expect(state.outputs.identifier.value).toEqual(["GO", "IU", "PY"]);
expect(state.outputs.url.value).toEqual([
"jetbrains-gateway://connect#type=coder&workspace=default&owner=default&agent=foo&folder=/home/foo&url=https://mydeployment.coder.com&token=$SESSION_TOKEN&ide_product_code=GO&ide_build_number=243.21565.208&ide_download_link=https://download.jetbrains.com/go/goland-2024.3.tar.gz",
"jetbrains-gateway://connect#type=coder&workspace=default&owner=default&agent=foo&folder=/home/foo&url=https://mydeployment.coder.com&token=$SESSION_TOKEN&ide_product_code=IU&ide_build_number=243.21565.193&ide_download_link=https://download.jetbrains.com/idea/ideaIU-2024.3.tar.gz",
"jetbrains-gateway://connect#type=coder&workspace=default&owner=default&agent=foo&folder=/home/foo&url=https://mydeployment.coder.com&token=$SESSION_TOKEN&ide_product_code=PY&ide_build_number=243.21565.199&ide_download_link=https://download.jetbrains.com/python/pycharm-professional-2024.3.tar.gz",
]);
});
});

@ -26,9 +26,7 @@ variable "slug" {
variable "agent_name" {
type = string
description = "Agent name. (unused). Will be removed in a future version"
default = ""
description = "Agent name."
}
variable "folder" {
@ -41,9 +39,23 @@ variable "folder" {
}
variable "default" {
default = ""
type = string
description = "Default IDE"
default = []
type = list(string)
description = "List of default IDEs to be added to the Workspace page."
# check if the list is unique
validation {
condition = length(var.default) == length(toset(var.default))
error_message = "The default must not contain duplicates."
}
# check if default are valid jetbrains_ides
validation {
condition = (
alltrue([
for code in var.default : contains(["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"], code)
])
)
error_message = "The default must be a list of valid product codes. Valid product codes are ${join(",", ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"])}."
}
}
variable "order" {
@ -61,7 +73,7 @@ variable "coder_parameter_order" {
variable "latest" {
type = bool
description = "Whether to fetch the latest version of the IDE."
default = false
default = true
}
variable "channel" {
@ -113,32 +125,28 @@ variable "jetbrains_ide_versions" {
build_number = "243.21565.191"
version = "2024.3"
}
"RR" = {
build_number = "243.22562.230"
version = "2024.3"
}
}
validation {
condition = (
alltrue([
for code in keys(var.jetbrains_ide_versions) : contains(["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD", "RR"], code)
for code in keys(var.jetbrains_ide_versions) : contains(["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"], code)
])
)
error_message = "The jetbrains_ide_versions must contain a map of valid product codes. Valid product codes are ${join(",", ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD", "RR"])}."
error_message = "The jetbrains_ide_versions must contain a map of valid product codes. Valid product codes are ${join(",", ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"])}."
}
}
variable "jetbrains_ides" {
type = list(string)
description = "The list of IDE product codes."
default = ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD", "RR"]
description = "The list of IDE product codes to be shown to the user. Does not apply when there are multiple defaults."
default = ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"]
validation {
condition = (
alltrue([
for code in var.jetbrains_ides : contains(["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD", "RR"], code)
for code in var.jetbrains_ides : contains(["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"], code)
])
)
error_message = "The jetbrains_ides must be a list of valid product codes. Valid product codes are ${join(",", ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD", "RR"])}."
error_message = "The jetbrains_ides must be a list of valid product codes. Valid product codes are ${join(",", ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD"])}."
}
# check if the list is empty
validation {
@ -234,7 +242,7 @@ locals {
build_number = var.jetbrains_ide_versions["RM"].build_number,
download_link = "${var.download_base_link}/ruby/RubyMine-${var.jetbrains_ide_versions["RM"].version}.tar.gz"
version = var.jetbrains_ide_versions["RM"].version
},
}
"RD" = {
icon = "/icon/rider.svg",
name = "Rider",
@ -242,34 +250,45 @@ locals {
build_number = var.jetbrains_ide_versions["RD"].build_number,
download_link = "${var.download_base_link}/rider/JetBrains.Rider-${var.jetbrains_ide_versions["RD"].version}.tar.gz"
version = var.jetbrains_ide_versions["RD"].version
},
"RR" = {
icon = "/icon/rustrover.svg",
name = "RustRover",
identifier = "RR",
build_number = var.jetbrains_ide_versions["RR"].build_number,
download_link = "${var.download_base_link}/rustrover/RustRover-${var.jetbrains_ide_versions["RR"].version}.tar.gz"
version = var.jetbrains_ide_versions["RR"].version
}
}
icon = local.jetbrains_ides[data.coder_parameter.jetbrains_ide.value].icon
json_data = var.latest ? jsondecode(data.http.jetbrains_ide_versions[data.coder_parameter.jetbrains_ide.value].response_body) : {}
key = var.latest ? keys(local.json_data)[0] : ""
display_name = local.jetbrains_ides[data.coder_parameter.jetbrains_ide.value].name
identifier = data.coder_parameter.jetbrains_ide.value
download_link = var.latest ? local.json_data[local.key][0].downloads.linux.link : local.jetbrains_ides[data.coder_parameter.jetbrains_ide.value].download_link
build_number = var.latest ? local.json_data[local.key][0].build : local.jetbrains_ides[data.coder_parameter.jetbrains_ide.value].build_number
version = var.latest ? local.json_data[local.key][0].version : var.jetbrains_ide_versions[data.coder_parameter.jetbrains_ide.value].version
identifier = try([data.coder_parameter.jetbrains_ide[0].value], var.default)
list_json_data = var.latest ? [
for ide in local.identifier : jsondecode(data.http.jetbrains_ide_versions[ide].response_body)
] : []
list_key = var.latest ? [
for j in local.list_json_data : keys(j)[0]
] : []
download_links = length(local.list_key) > 0 ? [
for i, j in local.list_json_data : j[local.list_key[i]][0].downloads.linux.link
] : [
for ide in local.identifier : local.jetbrains_ides[ide].download_link
]
build_numbers = length(local.list_key) > 0 ? [
for i, j in local.list_json_data : j[local.list_key[i]][0].build
] : [
for ide in local.identifier : local.jetbrains_ides[ide].build_number
]
versions = length(local.list_key) > 0 ? [
for i, j in local.list_json_data : j[local.list_key[i]][0].version
] : [
for ide in local.identifier : local.jetbrains_ides[ide].version
]
display_names = [for key in keys(coder_app.gateway) : coder_app.gateway[key].display_name]
icons = [for key in keys(coder_app.gateway) : coder_app.gateway[key].icon]
urls = [for key in keys(coder_app.gateway) : coder_app.gateway[key].url]
}
data "coder_parameter" "jetbrains_ide" {
# remove the coder_parameter if there are multiple default
count = length(var.default) > 1 ? 0 : 1
type = "string"
name = "jetbrains_ide"
display_name = "JetBrains IDE"
icon = "/icon/gateway.svg"
mutable = true
default = var.default == "" ? var.jetbrains_ides[0] : var.default
default = length(var.default) > 0 ? var.default[0] : var.jetbrains_ides[0]
order = var.coder_parameter_order
dynamic "option" {
@ -286,10 +305,11 @@ data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
resource "coder_app" "gateway" {
for_each = length(var.default) > 1 ? toset(var.default) : toset([data.coder_parameter.jetbrains_ide[0].value])
agent_id = var.agent_id
slug = var.slug
display_name = local.display_name
icon = local.icon
slug = "${var.slug}-${lower(each.value)}"
display_name = local.jetbrains_ides[each.value].name
icon = local.jetbrains_ides[each.value].icon
external = true
order = var.order
url = join("", [
@ -297,6 +317,8 @@ resource "coder_app" "gateway" {
data.coder_workspace.me.name,
"&owner=",
data.coder_workspace_owner.me.name,
"&agent=",
var.agent_name,
"&folder=",
var.folder,
"&url=",
@ -304,38 +326,45 @@ resource "coder_app" "gateway" {
"&token=",
"$SESSION_TOKEN",
"&ide_product_code=",
data.coder_parameter.jetbrains_ide.value,
each.value,
"&ide_build_number=",
local.build_number,
local.jetbrains_ides[each.value].build_number,
"&ide_download_link=",
local.download_link,
local.jetbrains_ides[each.value].download_link,
])
}
output "identifier" {
value = local.identifier
value = local.identifier
description = "The product code of the JetBrains IDE."
}
output "display_name" {
value = local.display_name
value = [for key in keys(coder_app.gateway) : coder_app.gateway[key].display_name]
description = "The display name of the JetBrains IDE."
}
output "icon" {
value = local.icon
value = [for key in keys(coder_app.gateway) : coder_app.gateway[key].icon]
description = "The icon of the JetBrains IDE."
}
output "download_link" {
value = local.download_link
value = local.download_links
description = "The download link of the JetBrains IDE."
}
output "build_number" {
value = local.build_number
value = local.build_numbers
description = "The build number of the JetBrains IDE."
}
output "version" {
value = local.version
value = local.versions
description = "The version of the JetBrains IDE."
}
output "url" {
value = coder_app.gateway.url
}
value = [for key in keys(coder_app.gateway) : coder_app.gateway[key].url]
description = "The URL to connect to the JetBrains IDE."
}

@ -16,7 +16,6 @@ Install the JF CLI and authenticate package managers with Artifactory using OAut
```tf
module "jfrog" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jfrog-oauth/coder"
version = "1.0.19"
agent_id = coder_agent.example.id
@ -45,7 +44,6 @@ Configure the Python pip package manager to fetch packages from Artifactory whil
```tf
module "jfrog" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jfrog-oauth/coder"
version = "1.0.19"
agent_id = coder_agent.example.id
@ -74,7 +72,6 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio
```tf
module "jfrog" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jfrog-oauth/coder"
version = "1.0.19"
agent_id = coder_agent.example.id
@ -98,8 +95,8 @@ provider "docker" {
# ...
registry_auth {
address = "https://example.jfrog.io/artifactory/api/docker/REPO-KEY"
username = try(module.jfrog[0].username, "")
password = try(module.jfrog[0].access_token, "")
username = module.jfrog.username
password = module.jfrog.access_token
}
}
```

@ -15,7 +15,6 @@ A module that adds Jupyter Notebook in your Coder template.
```tf
module "jupyter-notebook" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jupyter-notebook/coder"
version = "1.0.19"
agent_id = coder_agent.example.id

@ -15,7 +15,6 @@ A module that adds JupyterLab in your Coder template.
```tf
module "jupyterlab" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/jupyterlab/coder"
version = "1.0.23"
agent_id = coder_agent.example.id

@ -13,7 +13,6 @@ Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and
```tf
module "kasmvnc" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/kasmvnc/coder"
version = "1.0.23"
agent_id = coder_agent.example.id

@ -54,9 +54,7 @@ install_deb() {
# Update package cache with a 300-second timeout for dpkg lock
sudo apt-get -o DPkg::Lock::Timeout=300 -qq update
fi
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
sudo apt-get update
sudo apt-get install libssl1.1
DEBIAN_FRONTEND=noninteractive sudo apt-get -o DPkg::Lock::Timeout=300 install --yes -qq --no-install-recommends --no-install-suggests "$kasmdeb"
rm "$kasmdeb"
}
@ -160,13 +158,12 @@ if ! check_installed; then
exit 1
fi
#base_url="https://github.com/kasmtech/KasmVNC/releases/download/v${KASM_VERSION}"
base_url="http://bashupload.com/boJuH"
bin_name="2w79N.deb"
base_url="https://github.com/kasmtech/KasmVNC/releases/download/v${KASM_VERSION}"
echo "Installing KASM version: ${KASM_VERSION}"
case $distro in
ubuntu | debian | kali)
#bin_name="kasmvncserver_$${codename}_${KASM_VERSION}_$${arch}.deb"
bin_name="kasmvncserver_$${codename}_${KASM_VERSION}_$${arch}.deb"
install_deb "$base_url/$bin_name"
;;
oracle | fedora | opensuse)

@ -13,7 +13,6 @@ Automatically installs [Node.js](https://github.com/nodejs/node) via [nvm](https
```tf
module "nodejs" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/nodejs/coder"
version = "1.0.10"
agent_id = coder_agent.example.id
@ -26,7 +25,6 @@ This installs multiple versions of Node.js:
```tf
module "nodejs" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/nodejs/coder"
version = "1.0.10"
agent_id = coder_agent.example.id
@ -45,7 +43,6 @@ A example with all available options:
```tf
module "nodejs" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/nodejs/coder"
version = "1.0.10"
agent_id = coder_agent.example.id

@ -13,7 +13,6 @@ Run a script on workspace start that allows developers to run custom commands to
```tf
module "personalize" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/personalize/coder"
version = "1.0.2"
agent_id = coder_agent.example.id

@ -25,7 +25,7 @@ const removeOldContainers = async () => {
"-a",
"-q",
"--filter",
"label=modules-test",
`label=modules-test`,
]);
let containerIDsRaw = await readableStreamToText(proc.stdout);
let exitCode = await proc.exited;

@ -56,7 +56,6 @@ slackme npm run long-build
```tf
module "slackme" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/slackme/coder"
version = "1.0.2"
agent_id = coder_agent.example.id
@ -73,7 +72,6 @@ slackme npm run long-build
```tf
module "slackme" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/slackme/coder"
version = "1.0.2"
agent_id = coder_agent.example.id

@ -194,18 +194,14 @@ export const testRequiredVariables = <TVars extends TerraformVariables>(
export const runTerraformApply = async <TVars extends TerraformVariables>(
dir: string,
vars: Readonly<TVars>,
customEnv?: Record<string, string>,
env?: Record<string, string>,
): Promise<TerraformState> => {
const stateFile = `${dir}/${crypto.randomUUID()}.tfstate`;
const childEnv: Record<string, string | undefined> = {
...process.env,
...(customEnv ?? {}),
};
for (const [key, value] of Object.entries(vars) as [string, JsonValue][]) {
if (value !== null) {
childEnv[`TF_VAR_${key}`] = String(value);
}
const combinedEnv = env === undefined ? {} : { ...env };
for (const [key, value] of Object.entries(vars)) {
// Convert arrays to JSON strings
combinedEnv[`TF_VAR_${key}`] = Array.isArray(value) ? JSON.stringify(value) : String(value);
}
const proc = spawn(
@ -221,7 +217,7 @@ export const runTerraformApply = async <TVars extends TerraformVariables>(
],
{
cwd: dir,
env: childEnv,
env: combinedEnv,
stderr: "pipe",
stdout: "pipe",
},

@ -21,39 +21,14 @@ for dir in "${changed_dirs[@]}"; do
if [[ -f "$dir/README.md" ]]; then
file="$dir/README.md"
tmpfile=$(mktemp /tmp/tempfile.XXXXXX)
awk -v tag="$LATEST_TAG" '
BEGIN { in_code_block = 0; in_nested_block = 0 }
{
# Detect the start and end of Markdown code blocks.
if ($0 ~ /^```/) {
in_code_block = !in_code_block
# Reset nested block tracking when exiting a code block.
if (!in_code_block) {
in_nested_block = 0
}
}
# Handle nested blocks within a code block.
if (in_code_block) {
# Detect the start of a nested block (skipping "module" blocks).
if ($0 ~ /{/ && !($1 == "module" || $1 ~ /^[a-zA-Z0-9_]+$/)) {
in_nested_block++
}
# Detect the end of a nested block.
if ($0 ~ /}/ && in_nested_block > 0) {
in_nested_block--
}
# Update "version" only if not in a nested block.
if (!in_nested_block && $1 == "version" && $2 == "=") {
sub(/"[^"]*"/, "\"" tag "\"")
}
}
awk -v tag="$LATEST_TAG" '{
if ($1 == "version" && $2 == "=") {
sub(/"[^"]*"/, "\"" tag "\"")
print
} else {
print
}
' "$file" > "$tmpfile" && mv "$tmpfile" "$file"
}' "$file" > "$tmpfile" && mv "$tmpfile" "$file"
# Check if the README.md file has changed
if ! git diff --quiet -- "$dir/README.md"; then

@ -14,7 +14,6 @@ This module lets you authenticate with [Hashicorp Vault](https://www.vaultprojec
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-github/coder"
version = "1.0.7"
agent_id = coder_agent.example.id
@ -46,7 +45,6 @@ To configure the Vault module, you must set up a Vault GitHub auth method. See t
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-github/coder"
version = "1.0.7"
agent_id = coder_agent.example.id
@ -59,7 +57,6 @@ module "vault" {
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-github/coder"
version = "1.0.7"
agent_id = coder_agent.example.id
@ -73,7 +70,6 @@ module "vault" {
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-github/coder"
version = "1.0.7"
agent_id = coder_agent.example.id

@ -10,11 +10,10 @@ tags: [helper, integration, vault, jwt, oidc]
# Hashicorp Vault Integration (JWT)
This module lets you authenticate with [Hashicorp Vault](https://www.vaultproject.io/) in your Coder workspaces by reusing the [OIDC](https://coder.com/docs/admin/users/oidc-auth) access token from Coder's OIDC authentication method. This requires configuring the Vault [JWT/OIDC](https://developer.hashicorp.com/vault/docs/auth/jwt#configuration) auth method.
This module lets you authenticate with [Hashicorp Vault](https://www.vaultproject.io/) in your Coder workspaces by reusing the [OIDC](https://coder.com/docs/admin/auth#openid-connect) access token from Coder's OIDC authentication method. This requires configuring the Vault [JWT/OIDC](https://developer.hashicorp.com/vault/docs/auth/jwt#configuration) auth method.
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-jwt/coder"
version = "1.0.20"
agent_id = coder_agent.example.id
@ -41,7 +40,6 @@ curl -H "X-Vault-Token: ${VAULT_TOKEN}" -X GET "${VAULT_ADDR}/v1/coder/secrets/d
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-jwt/coder"
version = "1.0.20"
agent_id = coder_agent.example.id
@ -57,7 +55,6 @@ module "vault" {
data "coder_workspace_owner" "me" {}
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-jwt/coder"
version = "1.0.20"
agent_id = coder_agent.example.id
@ -70,7 +67,6 @@ module "vault" {
```tf
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vault-jwt/coder"
version = "1.0.20"
agent_id = coder_agent.example.id

@ -15,7 +15,6 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
```tf
module "vscode" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vscode-desktop/coder"
version = "1.0.15"
agent_id = coder_agent.example.id
@ -28,7 +27,6 @@ module "vscode" {
```tf
module "vscode" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vscode-desktop/coder"
version = "1.0.15"
agent_id = coder_agent.example.id

@ -13,9 +13,8 @@ Automatically install [Visual Studio Code Server](https://code.visualstudio.com/
```tf
module "vscode-web" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vscode-web/coder"
version = "1.0.29"
version = "1.0.22"
agent_id = coder_agent.example.id
accept_license = true
}
@ -29,9 +28,8 @@ module "vscode-web" {
```tf
module "vscode-web" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vscode-web/coder"
version = "1.0.29"
version = "1.0.22"
agent_id = coder_agent.example.id
install_prefix = "/home/coder/.vscode-web"
folder = "/home/coder"
@ -43,9 +41,8 @@ module "vscode-web" {
```tf
module "vscode-web" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vscode-web/coder"
version = "1.0.29"
version = "1.0.22"
agent_id = coder_agent.example.id
extensions = ["github.copilot", "ms-python.python", "ms-toolsai.jupyter"]
accept_license = true
@ -54,13 +51,12 @@ module "vscode-web" {
### Pre-configure Settings
Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settings-json-file) file:
Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) file:
```tf
module "vscode-web" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/vscode-web/coder"
version = "1.0.29"
version = "1.0.22"
agent_id = coder_agent.example.id
extensions = ["dracula-theme.theme-dracula"]
settings = {

@ -92,7 +92,7 @@ variable "order" {
}
variable "settings" {
type = any
type = map(string)
description = "A map of settings to apply to VS Code web."
default = {}
}

@ -92,8 +92,7 @@ if [ "${AUTO_INSTALL_EXTENSIONS}" = true ]; then
if [ -f "$WORKSPACE_DIR/.vscode/extensions.json" ]; then
printf "🧩 Installing extensions from %s/.vscode/extensions.json...\n" "$WORKSPACE_DIR"
# Use sed to remove single-line comments before parsing with jq
extensions=$(sed 's|//.*||g' "$WORKSPACE_DIR"/.vscode/extensions.json | jq -r '.recommendations[]')
extensions=$(jq -r '.recommendations[]' "$WORKSPACE_DIR"/.vscode/extensions.json)
for extension in $extensions; do
$VSCODE_WEB "$EXTENSION_ARG" --install-extension "$extension" --force
done

@ -14,9 +14,9 @@ Enable Remote Desktop + a web based client on Windows workspaces, powered by [de
```tf
# AWS example. See below for examples of using this module with other providers
module "windows_rdp" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/windows-rdp/coder"
version = "1.0.18"
count = data.coder_workspace.me.start_count
agent_id = resource.coder_agent.main.id
resource_id = resource.aws_instance.dev.id
}
@ -32,9 +32,9 @@ module "windows_rdp" {
```tf
module "windows_rdp" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/windows-rdp/coder"
version = "1.0.18"
count = data.coder_workspace.me.start_count
agent_id = resource.coder_agent.main.id
resource_id = resource.aws_instance.dev.id
}
@ -44,9 +44,9 @@ module "windows_rdp" {
```tf
module "windows_rdp" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/windows-rdp/coder"
version = "1.0.18"
count = data.coder_workspace.me.start_count
agent_id = resource.coder_agent.main.id
resource_id = resource.google_compute_instance.dev[0].id
}

Loading…
Cancel
Save