Merge branch 'main' into lint

pull/51/head
Muhammad Atif Ali 2 years ago committed by GitHub
commit ed59ede1d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xml:space="preserve"
width="560"
height="560"
version="1.1"
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
viewBox="0 0 560 560"
id="svg44"
sodipodi:docname="icon_raw.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
inkscape:export-filename="/home/umarcor/filebrowser/logo/icon_raw.svg.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><metadata
id="metadata48"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="711"
id="namedview46"
showgrid="false"
inkscape:zoom="0.33714286"
inkscape:cx="-172.33051"
inkscape:cy="280"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="svg44" />
<defs
id="defs4">
<style
type="text/css"
id="style2">
<![CDATA[
.fil1 {fill:#FEFEFE}
.fil6 {fill:#006498}
.fil7 {fill:#0EA5EB}
.fil8 {fill:#2979FF}
.fil3 {fill:#2BBCFF}
.fil0 {fill:#455A64}
.fil4 {fill:#53C6FC}
.fil5 {fill:#BDEAFF}
.fil2 {fill:#332C2B;fill-opacity:0.149020}
]]>
</style>
</defs>
<g
id="g85"
transform="translate(-70,-70)"><path
class="fil1"
d="M 350,71 C 504,71 629,196 629,350 629,504 504,629 350,629 196,629 71,504 71,350 71,196 196,71 350,71 Z"
id="path9"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil2"
d="M 475,236 593,387 C 596,503 444,639 301,585 L 225,486 339,330 c 0,0 138,-95 136,-94 z"
id="path11"
inkscape:connector-curvature="0"
style="fill:#332c2b;fill-opacity:0.14902003" /><path
class="fil3"
d="m 231,211 h 208 l 38,24 v 246 c 0,5 -3,8 -8,8 H 231 c -5,0 -8,-3 -8,-8 V 219 c 0,-5 3,-8 8,-8 z"
id="path13"
inkscape:connector-curvature="0"
style="fill:#2bbcff" /><path
class="fil4"
d="m 231,211 h 208 l 38,24 v 2 L 440,214 H 231 c -4,0 -7,3 -7,7 v 263 c -1,-1 -1,-2 -1,-3 V 219 c 0,-5 3,-8 8,-8 z"
id="path15"
inkscape:connector-curvature="0"
style="fill:#53c6fc" /><polygon
class="fil5"
points="305,212 418,212 418,310 305,310 "
id="polygon17"
style="fill:#bdeaff" /><path
class="fil5"
d="m 255,363 h 189 c 3,0 5,2 5,4 V 483 H 250 V 367 c 0,-2 2,-4 5,-4 z"
id="path19"
inkscape:connector-curvature="0"
style="fill:#bdeaff" /><polygon
class="fil6"
points="250,470 449,470 449,483 250,483 "
id="polygon21"
style="fill:#006498" /><path
class="fil6"
d="m 380,226 h 10 c 3,0 6,2 6,5 v 40 c 0,3 -3,6 -6,6 h -10 c -3,0 -6,-3 -6,-6 v -40 c 0,-3 3,-5 6,-5 z"
id="path23"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil1"
d="m 254,226 c 10,0 17,7 17,17 0,9 -7,16 -17,16 -9,0 -17,-7 -17,-16 0,-10 8,-17 17,-17 z"
id="path25"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil6"
d="m 267,448 h 165 c 2,0 3,1 3,3 v 0 c 0,1 -1,3 -3,3 H 267 c -2,0 -3,-2 -3,-3 v 0 c 0,-2 1,-3 3,-3 z"
id="path27"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil6"
d="m 267,415 h 165 c 2,0 3,1 3,3 v 0 c 0,1 -1,2 -3,2 H 267 c -2,0 -3,-1 -3,-2 v 0 c 0,-2 1,-3 3,-3 z"
id="path29"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil6"
d="m 267,381 h 165 c 2,0 3,2 3,3 v 0 c 0,2 -1,3 -3,3 H 267 c -2,0 -3,-1 -3,-3 v 0 c 0,-1 1,-3 3,-3 z"
id="path31"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil1"
d="m 236,472 c 3,0 5,2 5,5 0,2 -2,4 -5,4 -3,0 -5,-2 -5,-4 0,-3 2,-5 5,-5 z"
id="path33"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil1"
d="m 463,472 c 3,0 5,2 5,5 0,2 -2,4 -5,4 -3,0 -5,-2 -5,-4 0,-3 2,-5 5,-5 z"
id="path35"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><polygon
class="fil6"
points="305,212 284,212 284,310 305,310 "
id="polygon37"
style="fill:#006498" /><path
class="fil7"
d="m 477,479 v 2 c 0,5 -3,8 -8,8 H 231 c -5,0 -8,-3 -8,-8 v -2 c 0,4 3,8 8,8 h 238 c 5,0 8,-4 8,-8 z"
id="path39"
inkscape:connector-curvature="0"
style="fill:#0ea5eb" /><path
class="fil8"
d="M 350,70 C 505,70 630,195 630,350 630,505 505,630 350,630 195,630 70,505 70,350 70,195 195,70 350,70 Z m 0,46 C 479,116 584,221 584,350 584,479 479,584 350,584 221,584 116,479 116,350 116,221 221,116 350,116 Z"
id="path41"
inkscape:connector-curvature="0"
style="fill:#2979ff" /></g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

@ -61,7 +61,7 @@ resource "coder_script" "MODULE_NAME" {
LOG_PATH : var.log_path, LOG_PATH : var.log_path,
}) })
run_on_start = true run_on_start = true
run_on_stopt = false run_on_stop = false
} }
resource "coder_app" "MODULE_NAME" { resource "coder_app" "MODULE_NAME" {

@ -12,12 +12,6 @@ tags: [helper, parameter, regions, aws]
A parameter with all AWS regions. This allows developers to select A parameter with all AWS regions. This allows developers to select
the region closest to them. the region closest to them.
![AWS Regions](../.images/aws-region.png)
## Examples
### Default Region
Customize the preselected parameter value: Customize the preselected parameter value:
```hcl ```hcl
@ -31,6 +25,10 @@ provider "aws" {
} }
``` ```
![AWS Regions](../.images/aws-regions.png)
## Examples
### Customize Regions ### Customize Regions
Change the display name and icon for a region: Change the display name and icon for a region:

@ -11,10 +11,6 @@ tags: [helper, parameter, azure, regions]
This module adds a parameter with all Azure regions, allowing developers to select the region closest to them. This module adds a parameter with all Azure regions, allowing developers to select the region closest to them.
## Examples
### Default region
```hcl ```hcl
module "azure_region" { module "azure_region" {
source = "https://registry.coder.com/modules/azure-region" source = "https://registry.coder.com/modules/azure-region"
@ -26,6 +22,8 @@ resource "azurem_resource_group" "example" {
} }
``` ```
## Examples
### Customize existing regions ### Customize existing regions
Change the display name for a region: Change the display name for a region:

@ -22,6 +22,16 @@ module "code-server" {
## Examples ## Examples
### Pin Versions
```hcl
module "code-server" {
source = "https://registry.coder.com/modules/code-server"
agent_id = coder_agent.example.id
install_version = "4.8.3"
}
```
### Pre-install Extensions ### Pre-install Extensions
Install the Dracula theme from [OpenVSX](https://open-vsx.org/): Install the Dracula theme from [OpenVSX](https://open-vsx.org/):

@ -50,11 +50,18 @@ variable "log_path" {
default = "/tmp/code-server.log" default = "/tmp/code-server.log"
} }
variable "install_version" {
type = string
description = "The version of code-server to install."
default = ""
}
resource "coder_script" "code-server" { resource "coder_script" "code-server" {
agent_id = var.agent_id agent_id = var.agent_id
display_name = "code-server" display_name = "code-server"
icon = "/icon/code.svg" icon = "/icon/code.svg"
script = templatefile("${path.module}/run.sh", { script = templatefile("${path.module}/run.sh", {
VERSION : var.install_version,
EXTENSIONS : join(",", var.extensions), EXTENSIONS : join(",", var.extensions),
PORT : var.port, PORT : var.port,
LOG_PATH : var.log_path, LOG_PATH : var.log_path,
@ -69,7 +76,7 @@ resource "coder_app" "code-server" {
agent_id = var.agent_id agent_id = var.agent_id
slug = "code-server" slug = "code-server"
display_name = "code-server" display_name = "code-server"
url = "http://localhost:${var.port}/?folder=${var.folder}" url = "http://localhost:${var.port}/${var.folder != "" ? "?folder=${urlencode(var.folder)}" : ""}"
icon = "/icon/code.svg" icon = "/icon/code.svg"
subdomain = false subdomain = false
share = "owner" share = "owner"

@ -1,4 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env bash
EXTENSIONS=("${EXTENSIONS}") EXTENSIONS=("${EXTENSIONS}")
BOLD='\033[0;1m' BOLD='\033[0;1m'
@ -6,7 +6,16 @@ CODE='\033[36;40;1m'
RESET='\033[0m' RESET='\033[0m'
printf "$${BOLD}Installing code-server!\n" printf "$${BOLD}Installing code-server!\n"
output=$(curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=${INSTALL_PREFIX})
ARGS=(
"--method=standalone"
"--prefix=${INSTALL_PREFIX}"
)
if [ -n "${VERSION}" ]; then
ARGS+=("--version=${VERSION}")
fi
output=$(curl -fsSL https://code-server.dev/install.sh | sh -s -- "$${ARGS[@]}")
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed to install code-server: $output" echo "Failed to install code-server: $output"
exit 1 exit 1
@ -29,10 +38,10 @@ for extension in "$${EXTENSIONS[@]}"; do
done done
# Check if the settings file exists... # Check if the settings file exists...
if [ ! -f ~/.local/share/code-server/User/settings.json ]; then if [ ! -f ~/.local/share/code-server/Machine/settings.json ]; then
echo "⚙️ Creating settings file..." echo "⚙️ Creating settings file..."
mkdir -p ~/.local/share/code-server/User mkdir -p ~/.local/share/code-server/Machine
echo "${SETTINGS}" > ~/.local/share/code-server/User/settings.json echo "${SETTINGS}" > ~/.local/share/code-server/Machine/settings.json
fi fi
echo "👷 Running code-server in the background..." echo "👷 Running code-server in the background..."

@ -0,0 +1,31 @@
---
display_name: File Browser
description: A file browser for your workspace
icon: ../.icons/filebrowser.svg
maintainer_github: coder
verified: true
tags: [helper, filebrowser]
---
# File Browser
A file browser for your workspace.
```hcl
module "filebrowser" {
source = "https://registry.coder.com/modules/filebrowser"
agent_id = coder_agent.example.id
}
```
## Examples
### Serve a specific directory
```hcl
module "filebrowser" {
source = "https://registry.coder.com/modules/filebrowser"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
```

@ -0,0 +1,57 @@
terraform {
required_version = ">= 1.0"
required_providers {
coder = {
source = "coder/coder"
version = ">= 0.12"
}
}
}
# Add required variables for your modules and remove any unneeded variables
variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}
variable "log_path" {
type = string
description = "The path to log filebrowser to."
default = "/tmp/filebrowser.log"
}
variable "port" {
type = number
description = "The port to run filebrowser on."
default = 13339
}
variable "folder" {
type = string
description = "--root value for filebrowser."
default = "~"
}
resource "coder_script" "filebrowser" {
agent_id = var.agent_id
display_name = "File Browser"
icon = "https://raw.githubusercontent.com/filebrowser/logo/master/icon_raw.svg"
script = templatefile("${path.module}/run.sh", {
LOG_PATH : var.log_path,
PORT : var.port,
FOLDER : var.folder,
LOG_PATH : var.log_path,
})
run_on_start = true
}
resource "coder_app" "filebrowser" {
agent_id = var.agent_id
slug = "filebrowser"
display_name = "File Browser"
url = "http://localhost:${var.port}"
icon = "https://raw.githubusercontent.com/filebrowser/logo/master/icon_raw.svg"
subdomain = true
share = "owner"
}

@ -0,0 +1,21 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
echo "$${BOLD}Installing filebrowser \n\n"
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
echo "🥳 Installation comlete! \n\n"
echo "👷 Starting filebrowser in background... \n\n"
ROOT_DIR=${FOLDER}
ROOT_DIR=$${ROOT_DIR/\~/$HOME}
echo "📂 Serving $${ROOT_DIR} at http://localhost:${PORT} \n\n"
echo "Running 'filebrowser --noauth --root $ROOT_DIR --port ${PORT}' \n\n"
filebrowser --noauth --root $ROOT_DIR --port ${PORT} >${LOG_PATH} 2>&1 &
echo "📝 Logs at ${LOG_PATH} \n\n"

@ -4,17 +4,13 @@ description: A parameter with human region names and icons
icon: ../.icons/fly.svg icon: ../.icons/fly.svg
maintainer_github: coder maintainer_github: coder
verified: true verified: true
tags: [helper, parameter, fly] tags: [helper, parameter, fly.io, regions]
--- ---
# Fly.io Region # Fly.io Region
This module adds Fly.io regions to your Coder template. Regions can be whitelisted using the `regions` argument and given custom names and custom icons with their respective map arguments (`custom_names`, `custom_icons`). This module adds Fly.io regions to your Coder template. Regions can be whitelisted using the `regions` argument and given custom names and custom icons with their respective map arguments (`custom_names`, `custom_icons`).
## Examples
### Using default settings
We can use the simplest format here, only adding a default selection as the `atl` region. We can use the simplest format here, only adding a default selection as the `atl` region.
```hcl ```hcl
@ -26,6 +22,8 @@ module "fly-region" {
![Fly.io Default](../.images/flyio-basic.png) ![Fly.io Default](../.images/flyio-basic.png)
## Examples
### Using region whitelist ### Using region whitelist
The regions argument can be used to display only the desired regions in the Coder parameter. The regions argument can be used to display only the desired regions in the Coder parameter.

@ -11,38 +11,61 @@ tags: [gcp, regions, parameter, helper]
This module adds Google Cloud Platform regions to your Coder template. This module adds Google Cloud Platform regions to your Coder template.
```hcl
module "gcp_region" {
source = "https://registry.coder.com/modules/gcp-region"
regions = ["us", "europe"]
}
resource "google_compute_instance" "example" {
zone = module.gcp_region.value
}
```
![GCP Regions](../.images/gcp-regions.png) ![GCP Regions](../.images/gcp-regions.png)
## Examples ## Examples
1. Add only GPU zones in the US West 1 region: ### Add only GPU zones in the US West 1 region
```hcl ```hcl
module "gcp_region" { module "gcp_region" {
source = "https://registry.coder.com/modules/gcp-region" source = "https://registry.coder.com/modules/gcp-region"
default = ["us-west1-a"] default = ["us-west1-a"]
regions = ["us-west1"] regions = ["us-west1"]
gpu_only = false gpu_only = false
} }
```
resource "google_compute_instance" "example" {
2. Add all zones in the Europe West region: zone = module.gcp_region.value
}
```hcl ```
module "gcp_region" {
source = "https://registry.coder.com/modules/gcp-region" ### Add all zones in the Europe West region
regions = ["europe-west"]
single_zone_per_region = false ```hcl
} module "gcp_region" {
``` source = "https://registry.coder.com/modules/gcp-region"
regions = ["europe-west"]
3. Add a single zone from each region in US and Europe that laos has GPUs single_zone_per_region = false
}
```hcl
module "gcp_region" { resource "google_compute_instance" "example" {
source = "https://registry.coder.com/modules/gcp-region" zone = module.gcp_region.value
regions = ["us", "europe"] }
gpu_only = true ```
single_zone_per_region = true
} ### Add a single zone from each region in US and Europe that laos has GPUs
```
```hcl
module "gcp_region" {
source = "https://registry.coder.com/modules/gcp-region"
regions = ["us", "europe"]
gpu_only = true
single_zone_per_region = true
}
resource "google_compute_instance" "example" {
zone = module.gcp_region.value
}
```

@ -13,8 +13,9 @@ This module allows you to automatically clone a repository by URL and skip if it
```hcl ```hcl
module "git-clone" { module "git-clone" {
source = "https://registry.coder.com/modules/git-clone" source = "https://registry.coder.com/modules/git-clone"
url = "https://github.com/coder/coder" agent_id = coder_agent.example.id
url = "https://github.com/coder/coder"
} }
``` ```
@ -32,8 +33,9 @@ data "coder_git_auth" "github" {
```hcl ```hcl
module "git-clone" { module "git-clone" {
source = "https://registry.coder.com/modules/git-clone" source = "https://registry.coder.com/modules/git-clone"
url = "https://github.com/coder/coder" agent_id = coder_agent.example.id
path = "~/projects/coder/coder" url = "https://github.com/coder/coder"
path = "~/projects/coder/coder"
} }
``` ```

@ -11,6 +11,16 @@ tags: [ide, jetbrains, helper, parameter]
This module adds a JetBrains Gateway Button to open any workspace with a single click. This module adds a JetBrains Gateway Button to open any workspace with a single click.
```hcl
module "jetbrains_gateway" {
source = "https://registry.coder.com/modules/jetbrains-gateway"
agent_id = coder_agent.example.id
agent_name = "example"
project_directory = "/home/coder/example"
jetbrains_ides = ["GO", "WS", "IU", "IC", "PY", "PC", "PS", "CL", "RM", "DB", "RD"]
}
```
![JetBrains Gateway IDes list](../.images/jetbrains-gateway.png) ![JetBrains Gateway IDes list](../.images/jetbrains-gateway.png)
## Examples ## Examples

@ -25,6 +25,7 @@ variable "project_directory" {
} }
variable "default" { variable "default" {
default = null
type = string type = string
description = "Default IDE" description = "Default IDE"
} }
@ -38,7 +39,17 @@ variable "jetbrains_ides" {
for code in var.jetbrains_ides : contains(["IU", "IC", "PS", "WS", "PY", "PC", "CL", "GO", "DB", "RD", "RM"], code) for code in var.jetbrains_ides : contains(["IU", "IC", "PS", "WS", "PY", "PC", "CL", "GO", "DB", "RD", "RM"], code)
]) ])
) )
error_message = "The jetbrains_ides must be a list of valid product codes. https://plugins.jetbrains.com/docs/marketplace/product-codes.html" error_message = "The jetbrains_ides must be a list of valid product codes. Valid product codes are: IU, IC, PS, WS, PY, PC, CL, GO, DB, RD, RM."
}
# check if the list is empty
validation {
condition = length(var.jetbrains_ides) > 0
error_message = "The jetbrains_ides must not be empty."
}
#ccheck if the list contains duplicates
validation {
condition = length(var.jetbrains_ides) == length(toset(var.jetbrains_ides))
error_message = "The jetbrains_ides must not contain duplicates."
} }
} }
@ -108,7 +119,8 @@ data "coder_parameter" "jetbrains_ide" {
display_name = "JetBrains IDE" display_name = "JetBrains IDE"
icon = "/icon/gateway.svg" icon = "/icon/gateway.svg"
mutable = true mutable = true
default = var.default != null && var.default != "" ? local.jetbrains_ides[var.default].value : null # check if default is in the jet_brains_ides list and if it is not empty or null otherwise set it to null
default = var.default != null && var.default != "" && contains(var.jetbrains_ides, var.default) ? local.jetbrains_ides[var.default].value : null
dynamic "option" { dynamic "option" {
for_each = { for key, value in local.jetbrains_ides : key => value if contains(var.jetbrains_ides, key) } for_each = { for key, value in local.jetbrains_ides : key => value if contains(var.jetbrains_ides, key) }
@ -126,9 +138,26 @@ resource "coder_app" "gateway" {
agent_id = var.agent_id agent_id = var.agent_id
display_name = data.coder_parameter.jetbrains_ide.option[index(data.coder_parameter.jetbrains_ide.option.*.value, data.coder_parameter.jetbrains_ide.value)].name display_name = data.coder_parameter.jetbrains_ide.option[index(data.coder_parameter.jetbrains_ide.option.*.value, data.coder_parameter.jetbrains_ide.value)].name
slug = "gateway" slug = "gateway"
url = "jetbrains-gateway://connect#type=coder&workspace=${data.coder_workspace.me.name}&agent=${var.agent_name}&folder=${var.project_directory}&url=${data.coder_workspace.me.access_url}&token=${data.coder_workspace.me.owner_session_token}&ide_product_code=${jsondecode(data.coder_parameter.jetbrains_ide.value)[0]}&ide_build_number=${jsondecode(data.coder_parameter.jetbrains_ide.value)[1]}&ide_download_link=${jsondecode(data.coder_parameter.jetbrains_ide.value)[2]}"
icon = data.coder_parameter.jetbrains_ide.option[index(data.coder_parameter.jetbrains_ide.option.*.value, data.coder_parameter.jetbrains_ide.value)].icon icon = data.coder_parameter.jetbrains_ide.option[index(data.coder_parameter.jetbrains_ide.option.*.value, data.coder_parameter.jetbrains_ide.value)].icon
external = true external = true
url = join("", [
"jetbrains-gateway://connect#type=coder&workspace=",
data.coder_workspace.me.name,
"&agent=",
var.agent_name,
"&folder=",
var.project_directory,
"&url=",
data.coder_workspace.me.access_url,
"&token=",
"$SESSION_TOKEN",
"&ide_product_code=",
jsondecode(data.coder_parameter.jetbrains_ide.value)[0],
"&ide_build_number=",
jsondecode(data.coder_parameter.jetbrains_ide.value)[1],
"&ide_download_link=",
jsondecode(data.coder_parameter.jetbrains_ide.value)[2]
])
} }
output "jetbrains_ides" { output "jetbrains_ides" {

@ -10,4 +10,47 @@ tags: [integration]
# JFrog # JFrog
TODO Install the JF CLI and authenticate package managers with Artifactory.
```hcl
module "jfrog" {
source = "https://registry.coder.com/modules/jfrog"
agent_id = coder_agent.example.id
jfrog_url = "https://YYYY.jfrog.io"
artifactory_access_token = var.artifactory_access_token # An admin access token
package_managers = {
"npm": "npm-remote",
"go": "go-remote",
"pypi": "pypi-remote"
}
}
```
Get a JFrog access token from your Artifactory instance. The token must have admin permissions. It is recommended to store the token in a secret terraform variable.
```hcl
variable "artifactory_access_token" {
type = string
sensitive = true
}
```
![JFrog](../.images/jfrog.png)
## Examples
### Configure npm, go, and pypi to use Artifactory local repositories
```hcl
module "jfrog" {
source = "https://registry.coder.com/modules/jfrog"
agent_id = coder_agent.example.id
jfrog_url = "https://YYYY.jfrog.io"
artifactory_access_token = var.artifactory_access_token # An admin access token
package_managers = {
"npm": "npm-local",
"go": "go-local",
"pypi": "pypi-local"
}
}
```

@ -0,0 +1,41 @@
import { serve } from "bun";
import { describe } from "bun:test";
import {
createJSONResponse,
runTerraformInit,
testRequiredVariables,
} from "../test";
describe("jfrog", async () => {
await runTerraformInit(import.meta.dir);
// Run a fake JFrog server so the provider can initialize
// correctly. This saves us from having to make remote requests!
const fakeFrogHost = serve({
fetch: (req) => {
const url = new URL(req.url);
// See https://jfrog.com/help/r/jfrog-rest-apis/license-information
if (url.pathname === "/artifactory/api/system/license")
return createJSONResponse({
type: "Commercial",
licensedTo: "JFrog inc.",
validThrough: "May 15, 2036",
});
if (url.pathname === "/access/api/v1/tokens")
return createJSONResponse({
token_id: "xxx",
access_token: "xxx",
scope: "any",
});
return createJSONResponse({});
},
port: 0,
});
testRequiredVariables(import.meta.dir, {
agent_id: "some-agent-id",
jfrog_url: "http://" + fakeFrogHost.hostname + ":" + fakeFrogHost.port,
artifactory_access_token: "XXXX",
package_managers: "{}",
});
});

@ -0,0 +1,71 @@
terraform {
required_version = ">= 1.0"
required_providers {
coder = {
source = "coder/coder"
version = ">= 0.12"
}
artifactory = {
source = "registry.terraform.io/jfrog/artifactory"
version = "~> 8.4.0"
}
}
}
variable "jfrog_url" {
type = string
description = "JFrog instance URL. e.g. https://YYY.jfrog.io"
}
variable "artifactory_access_token" {
type = string
description = "The admin-level access token to use for JFrog."
}
# Configure the Artifactory provider
provider "artifactory" {
url = join("/", [var.jfrog_url, "artifactory"])
access_token = var.artifactory_access_token
}
resource "artifactory_scoped_token" "me" {
# This is hacky, but on terraform plan the data source gives empty strings,
# which fails validation.
username = length(data.coder_workspace.me.owner_email) > 0 ? data.coder_workspace.me.owner_email : "plan"
}
variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}
variable "package_managers" {
type = map(string)
description = <<EOF
A map of package manager names to their respective artifactory repositories.
For example:
{
"npm": "npm-local",
"go": "go-local",
"pypi": "pypi-local"
}
EOF
}
data "coder_workspace" "me" {}
resource "coder_script" "jfrog" {
agent_id = var.agent_id
display_name = "jfrog"
icon = "/icon/jfrog.svg"
script = templatefile("${path.module}/run.sh", {
JFROG_URL : var.jfrog_url,
JFROG_HOST : replace(var.jfrog_url, "https://", ""),
ARTIFACTORY_USERNAME : data.coder_workspace.me.owner_email,
ARTIFACTORY_ACCESS_TOKEN : artifactory_scoped_token.me.access_token,
REPOSITORY_NPM : lookup(var.package_managers, "npm", ""),
REPOSITORY_GO : lookup(var.package_managers, "go", ""),
REPOSITORY_PYPI : lookup(var.package_managers, "pypi", ""),
})
run_on_start = true
}

@ -0,0 +1,49 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
echo "$${BOLD}Installing JFrog CLI..."
# Install the JFrog CLI.
curl -fL https://install-cli.jfrog.io | sudo sh
sudo chmod 755 /usr/local/bin/jf
# The jf CLI checks $CI when determining whether to use interactive
# flows.
export CI=true
# Authenticate with the JFrog CLI.
jf c rm 0 || true
echo "${ARTIFACTORY_ACCESS_TOKEN}" | jf c add --access-token-stdin --url "${JFROG_URL}" 0
# Configure the `npm` CLI to use the Artifactory "npm" repository.
if [ -z "${REPOSITORY_NPM}" ]; then
echo "🤔 REPOSITORY_NPM is not set, skipping npm configuration."
else
echo "📦 Configuring npm..."
jf npmc --global --repo-resolve "${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM}"
cat << EOF > ~/.npmrc
email = ${ARTIFACTORY_USERNAME}
registry = ${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM}
EOF
jf rt curl /api/npm/auth >> ~/.npmrc
fi
# Configure the `pip` to use the Artifactory "python" repository.
if [ -z "${REPOSITORY_PYPI}" ]; then
echo "🤔 REPOSITORY_PYPI is not set, skipping pip configuration."
else
echo "🐍 Configuring pip..."
mkdir -p ~/.pip
cat << EOF > ~/.pip/pip.conf
[global]
index-url = https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/pypi/${REPOSITORY_PYPI}/simple
EOF
fi
# Set GOPROXY to use the Artifactory "go" repository.
if [ -z "${REPOSITORY_GO}" ]; then
echo "🤔 REPOSITORY_GO is not set, skipping go configuration."
else
echo "🐹 Configuring go..."
export GOPROXY="https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/go/${REPOSITORY_GO}"
fi
echo "🥳 Configuration complete!"

@ -1,4 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env bash
# This scripts creates a new sample moduledir with requried files # This scripts creates a new sample moduledir with requried files
# Run it like : ./new.sh my-module # Run it like : ./new.sh my-module

@ -32,6 +32,7 @@ export const runContainer = async (
export const executeScriptInContainer = async ( export const executeScriptInContainer = async (
state: TerraformState, state: TerraformState,
image: string, image: string,
shell: string = "sh",
): Promise<{ ): Promise<{
exitCode: number; exitCode: number;
stdout: string[]; stdout: string[];
@ -39,7 +40,7 @@ export const executeScriptInContainer = async (
}> => { }> => {
const instance = findResourceInstance(state, "coder_script"); const instance = findResourceInstance(state, "coder_script");
const id = await runContainer(image); const id = await runContainer(image);
const resp = await execContainer(id, ["sh", "-c", instance.script]); const resp = await execContainer(id, [shell, "-c", instance.script]);
const stdout = resp.stdout.trim().split("\n"); const stdout = resp.stdout.trim().split("\n");
const stderr = resp.stderr.trim().split("\n"); const stderr = resp.stderr.trim().split("\n");
return { return {
@ -153,7 +154,7 @@ export const testRequiredVariables = (
await runTerraformApply(dir, localVars); await runTerraformApply(dir, localVars);
} catch (ex) { } catch (ex) {
expect(ex.message).toContain( expect(ex.message).toContain(
`input variable \"${varName}\" is not set, and has no default`, `input variable \"${varName}\" is not set`,
); );
return; return;
} }
@ -180,6 +181,7 @@ export const runTerraformApply = async (
"-input=false", "-input=false",
"-auto-approve", "-auto-approve",
"-state", "-state",
"-no-color",
stateFile, stateFile,
], ],
{ {
@ -210,3 +212,12 @@ export const runTerraformInit = async (dir: string) => {
throw new Error(text); throw new Error(text);
} }
}; };
export const createJSONResponse = (obj: object, statusCode = 200): Response => {
return new Response(JSON.stringify(obj), {
headers: {
"Content-Type": "application/json",
},
status: statusCode,
})
}

@ -1,38 +0,0 @@
---
display_name: vscode-server
description: VS Code Web - Visual Studio Code in the browser
icon: ../.icons/code.svg
maintainer_github: coder
verified: true
tags: [helper, ide, vscode, web]
---
# VS Code Web
Automatically install [Visual Studio Code Server](https://code.visualstudio.com/docs/remote/vscode-server) in a workspace using the [VS Code CLIs](https://code.visualstudio.com/docs/editor/command-line) and create an app to access it via the dashboard.
![VS Code Server with GitHub Copilot and live-share](../.images/vscode-server.gif)
## Examples
1. Install VS Code Server with default settings:
```hcl
module "vscode-web" {
source = "https://registry.coder.com/modules/vscode-server"
agent_id = coder_agent.example.id
accept_license = true
}
```
2. Install VS Code Server to a custom folder:
```hcl
module "vscode-web" {
source = "https://registry.coder.com/modules/vscode-server"
agent_id = coder_agent.example.id
install_dir = "/home/coder/.vscode-server"
folder = "/home/coder"
accept_license = true
}
```

@ -0,0 +1,36 @@
---
display_name: VS Code Web
description: VS Code Web - Visual Studio Code in the browser
icon: ../.icons/code.svg
maintainer_github: coder
verified: true
tags: [helper, ide, vscode, web]
---
# VS Code Web
Automatically install [Visual Studio Code Server](https://code.visualstudio.com/docs/remote/vscode-server) in a workspace using the [VS Code CLI](https://code.visualstudio.com/docs/editor/command-line) and create an app to access it via the dashboard.
```hcl
module "vscode-web" {
source = "https://registry.coder.com/modules/vscode-server"
agent_id = coder_agent.example.id
accept_license = true
}
```
![VS Code Server with GitHub Copilot and live-share](../.images/vscode-server.gif)
## Examples
### Install VS Code Server to a custom folder
```hcl
module "vscode-web" {
source = "https://registry.coder.com/modules/vscode-server"
agent_id = coder_agent.example.id
install_dir = "/home/coder/.vscode-server"
folder = "/home/coder"
accept_license = true
}
```

@ -22,14 +22,14 @@ variable "port" {
variable "folder" { variable "folder" {
type = string type = string
description = "The folder to open in vscode-server." description = "The folder to open in vscode-web."
default = "" default = ""
} }
variable "log_path" { variable "log_path" {
type = string type = string
description = "The path to log." description = "The path to log."
default = "/tmp/vscode-server.log" default = "/tmp/vscode-web.log"
} }
variable "install_dir" { variable "install_dir" {
@ -48,7 +48,7 @@ variable "accept_license" {
} }
} }
resource "coder_script" "vscode-server" { resource "coder_script" "vscode-web" {
agent_id = var.agent_id agent_id = var.agent_id
display_name = "VS Code Web" display_name = "VS Code Web"
icon = "/icon/code.svg" icon = "/icon/code.svg"
@ -60,9 +60,9 @@ resource "coder_script" "vscode-server" {
run_on_start = true run_on_start = true
} }
resource "coder_app" "vscode-server" { resource "coder_app" "vscode-web" {
agent_id = var.agent_id agent_id = var.agent_id
slug = "vscode-server" slug = "vscode-web"
display_name = "VS Code Web" display_name = "VS Code Web"
url = var.folder == "" ? "http://localhost:${var.port}" : "http://localhost:${var.port}?folder=${var.folder}" url = var.folder == "" ? "http://localhost:${var.port}" : "http://localhost:${var.port}?folder=${var.folder}"
icon = "/icon/code.svg" icon = "/icon/code.svg"
Loading…
Cancel
Save