Skip to content

Commit abd8c80

Browse files
committed
feat: combine module from coder
1 parent a355004 commit abd8c80

File tree

10 files changed

+473
-383
lines changed

10 files changed

+473
-383
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.terraform*

.gitpod.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
tasks:
2+
- name: Install Terraform CLI
3+
command: |
4+
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
5+
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
6+
sudo apt update && sudo apt install terraform
7+
terraform init
8+
9+
vscode:
10+
extensions:
11+
- hashicorp.terraform
12+
- hashicorp.hcl

LICENSE

Lines changed: 21 additions & 373 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
<div align="center">
33

44
<!-- <a href="#">
5-
<img src="https://github.com/katorlys/.github/blob/main/assets/logo/logo.png" height="100">
5+
<img src="https://github.com/katorlys/.github/blob/main/assets/mark/mark.png" height="100">
66
</a><br> -->
77

88
<h1>
9-
ExampleProject
9+
Coder Dotfiles after VS Code Module
1010
</h1>
1111

1212
<p>
13-
One sentence to describe project
13+
Terraform Module to install dotfiles after vscode-web installation in Coderv2.
1414
</p>
1515

1616
[![Pull Requests][github-pr-badge]][github-pr-link]
@@ -23,7 +23,37 @@
2323
<!-- Main Body -->
2424

2525
## Introduction
26-
Describe your project clearly here.
26+
This module is copied from [Coder VS Code Web Module](https://registry.coder.com/modules/vscode-web) and [Coder Dotfiles Module](https://registry.coder.com/modules/dotfiles) (Both licensed under [Apache License 2.0](https://github.com/coder/modules/blob/438c9045673c629e95416960c94a6b6344e3d298/LICENSE)), and adds the feature of executing the dotfiles install script after VS Code web installation.
27+
28+
This is a temporary fix for issue [https://github.com/coder/coder/issues](https://github.com/coder/coder/issues)#10352.
29+
30+
By using this module, you don't need to use the Coder VS Code Web Module and Coder Dotfiles Module anymore, and you'll never see `/tmp/vscode-web/bin/code-server: 12: /tmp/vscode-web/node: Text file busy` if you want to install VS Code installation in Coderv2 from your dotfiles now.
31+
32+
33+
## Examples
34+
Combine [Coder VS Code Web Module](https://registry.coder.com/modules/vscode-web?tab=readme) and [Coder Dotfiles Module](https://registry.coder.com/modules/dotfiles?tab=readme) together.
35+
```tf
36+
module "dotfiles-after-vscode-web" {
37+
source = "katorlys-samples/dotfiles-after-vscode-web/coder"
38+
version = "0.1.0"
39+
agent_id = coder_agent.example.id
40+
folder = "/home/coder"
41+
accept_license = true
42+
}
43+
```
44+
45+
46+
## How?
47+
This modules combines the Coder VS Code Web Module and Coder Dotfiles Module together in one module. Then, it executes the original dotfiles install script right after VS Code web install script is done. (See [run.sh](/run.sh) for detailed information)
48+
49+
50+
## Why?
51+
I initially intended to fix the issue privately. However, the shell scripts on Windows use `\r\n` for End of Line instead of `\n`, and Coder cannot automatically convert them, causing script execution to fail.
52+
53+
Since I deploy the Coder instance using Docker, I can only copy the script to the online editor. Additionally, the `Upload template` function is broken, preventing me from packaging and uploading the scripts.
54+
55+
All attempts failed, so I had no choice but to publish a module from Git to avoid the End of Line issue.
56+
2757

2858
<!-- /Main Body -->
2959

@@ -47,11 +77,11 @@ Describe your project clearly here.
4777
</div>
4878

4979
[back-to-top-button]: https://img.shields.io/badge/BACK_TO_TOP-151515?style=flat-square
50-
[github-pr-badge]: https://img.shields.io/github/issues-pr/katorlys/ExampleProject?label=pulls&labelColor=151515&color=79E096&style=flat-square
51-
[github-pr-link]: https://github.com/katorlys/ExampleProject/pulls
52-
[github-issue-badge]: https://img.shields.io/github/issues/katorlys/ExampleProject?labelColor=151515&color=FFC868&style=flat-square
53-
[github-issue-link]: https://github.com/katorlys/ExampleProject/issues
54-
[github-license-badge]: https://img.shields.io/github/license/katorlys/ExampleProject?labelColor=151515&color=EFEFEF&style=flat-square
80+
[github-pr-badge]: https://img.shields.io/github/issues-pr/katorlys-samples/terraform-coder-dotfileswithchecks?label=pulls&labelColor=151515&color=79E096&style=flat-square
81+
[github-pr-link]: https://github.com/katorlys-samples/terraform-coder-dotfileswithchecks/pulls
82+
[github-issue-badge]: https://img.shields.io/github/issues/katorlys-samples/terraform-coder-dotfileswithchecks?labelColor=151515&color=FFC868&style=flat-square
83+
[github-issue-link]: https://github.com/katorlys-samples/terraform-coder-dotfileswithchecks/issues
84+
[github-license-badge]: https://img.shields.io/github/license/katorlys-samples/terraform-coder-dotfileswithchecks?labelColor=151515&color=EFEFEF&style=flat-square
5585
<!-- https://img.shields.io/badge/license-CC_BY--NC--SA_4.0-EFEFEF?labelColor=151515&style=flat-square -->
56-
[github-license-badge-bottom]: https://img.shields.io/github/license/katorlys/ExampleProject?labelColor=151515&color=EFEFEF&style=for-the-badge
86+
[github-license-badge-bottom]: https://img.shields.io/github/license/katorlys-samples/terraform-coder-dotfileswithchecks?labelColor=151515&color=EFEFEF&style=for-the-badge
5787
<!-- https://img.shields.io/badge/license-CC_BY--NC--SA_4.0-EFEFEF?labelColor=151515&style=for-the-badge -->

dotfiles_run.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env bash
2+
DOTFILES_URI="${DOTFILES_URI}"
3+
DOTFILES_USER="${DOTFILES_USER}"
4+
5+
if [ -n "$${DOTFILES_URI// }" ]; then
6+
if [ -z "$DOTFILES_USER" ]; then
7+
DOTFILES_USER="$USER"
8+
fi
9+
10+
echo "✨ Applying dotfiles for user $DOTFILES_USER"
11+
12+
if [ "$DOTFILES_USER" = "$USER" ]; then
13+
coder dotfiles "$DOTFILES_URI" -y 2>&1 | tee ~/.dotfiles.log
14+
else
15+
# The `eval echo ~"$DOTFILES_USER"` part is used to dynamically get the home directory of the user, see https://superuser.com/a/484280
16+
# eval echo ~coder -> "/home/coder"
17+
# eval echo ~root -> "/root"
18+
19+
CODER_BIN=$(which coder)
20+
DOTFILES_USER_HOME=$(eval echo ~"$DOTFILES_USER")
21+
sudo -u "$DOTFILES_USER" sh -c "'$CODER_BIN' dotfiles '$DOTFILES_URI' -y 2>&1 | tee '$DOTFILES_USER_HOME'/.dotfiles.log"
22+
fi
23+
fi

main.tf

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
coder = {
6+
source = "coder/coder"
7+
version = ">= 0.17"
8+
}
9+
}
10+
}
11+
12+
resource "coder_script" "dotfiles-after-vscode-web" {
13+
agent_id = var.agent_id
14+
display_name = "VS Code Web"
15+
icon = "/icon/code.svg"
16+
script = templatefile("${path.module}/run.sh", {
17+
PORT : var.port,
18+
LOG_PATH : var.log_path,
19+
INSTALL_PREFIX : var.install_prefix,
20+
EXTENSIONS : join(",", var.extensions),
21+
TELEMETRY_LEVEL : var.telemetry_level,
22+
SETTINGS : replace(jsonencode(var.settings), "\"", "\\\""),
23+
OFFLINE : var.offline,
24+
USE_CACHED : var.use_cached,
25+
EXTENSIONS_DIR : var.extensions_dir,
26+
FOLDER : var.folder,
27+
AUTO_INSTALL_EXTENSIONS : var.auto_install_extensions,
28+
DOTFILES_URI : local.dotfiles_uri,
29+
DOTFILES_USER : local.user
30+
})
31+
run_on_start = true
32+
33+
lifecycle {
34+
precondition {
35+
condition = !var.offline || length(var.extensions) == 0
36+
error_message = "Offline mode does not allow extensions to be installed"
37+
}
38+
39+
precondition {
40+
condition = !var.offline || !var.use_cached
41+
error_message = "Offline and Use Cached can not be used together"
42+
}
43+
}
44+
}
45+
46+
resource "coder_app" "vscode-web" {
47+
agent_id = var.agent_id
48+
slug = var.vscode_slug
49+
display_name = var.vscode_display_name
50+
url = var.folder == "" ? "http://localhost:${var.port}" : "http://localhost:${var.port}?folder=${var.folder}"
51+
icon = "/icon/code.svg"
52+
subdomain = true
53+
share = var.share
54+
order = var.order
55+
56+
healthcheck {
57+
url = "http://localhost:${var.port}/healthz"
58+
interval = 5
59+
threshold = 6
60+
}
61+
}
62+
63+
data "coder_parameter" "dotfiles_uri" {
64+
count = var.dotfiles_uri == null ? 1 : 0
65+
type = "string"
66+
name = "dotfiles_uri"
67+
display_name = "Dotfiles URL"
68+
order = var.coder_parameter_order
69+
default = var.default_dotfiles_uri
70+
description = "Enter a URL for a [dotfiles repository](https://dotfiles.github.io) to personalize your workspace"
71+
mutable = true
72+
icon = "/icon/dotfiles.svg"
73+
}
74+
75+
locals {
76+
dotfiles_uri = var.dotfiles_uri != null ? var.dotfiles_uri : data.coder_parameter.dotfiles_uri[0].value
77+
user = var.user != null ? var.user : ""
78+
}
79+
80+
# resource "coder_script" "dotfiles" {
81+
# agent_id = var.agent_id
82+
# script = templatefile("${path.module}/dotfiles_run.sh", {
83+
# DOTFILES_URI : local.dotfiles_uri,
84+
# DOTFILES_USER : local.user
85+
# })
86+
# display_name = "Dotfiles"
87+
# icon = "/icon/dotfiles.svg"
88+
# run_on_start = true
89+
# depends_on = [ coder_script.vscode-web ]
90+
# }
91+
92+
resource "coder_app" "dotfiles" {
93+
count = var.manual_update ? 1 : 0
94+
agent_id = var.agent_id
95+
display_name = "Refresh Dotfiles"
96+
slug = "dotfiles"
97+
icon = "/icon/dotfiles.svg"
98+
command = templatefile("${path.module}/dotfiles_run.sh", {
99+
DOTFILES_URI : local.dotfiles_uri,
100+
DOTFILES_USER : local.user
101+
})
102+
}

outputs.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output "dotfiles_uri" {
2+
description = "Dotfiles URI"
3+
value = local.dotfiles_uri
4+
}

run.sh

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env bash
2+
3+
BOLD='\033[0;1m'
4+
EXTENSIONS=("${EXTENSIONS}")
5+
VSCODE_WEB="${INSTALL_PREFIX}/bin/code-server"
6+
7+
# Set extension directory
8+
EXTENSION_ARG=""
9+
if [ -n "${EXTENSIONS_DIR}" ]; then
10+
EXTENSION_ARG="--extensions-dir=${EXTENSIONS_DIR}"
11+
fi
12+
13+
run_vscode_web() {
14+
echo "👷 Running $VSCODE_WEB serve-local $EXTENSION_ARG --port ${PORT} --host 127.0.0.1 --accept-server-license-terms --without-connection-token --telemetry-level ${TELEMETRY_LEVEL} in the background..."
15+
echo "Check logs at ${LOG_PATH}!"
16+
"$VSCODE_WEB" serve-local "$EXTENSION_ARG" --port "${PORT}" --host 127.0.0.1 --accept-server-license-terms --without-connection-token --telemetry-level "${TELEMETRY_LEVEL}" > "${LOG_PATH}" 2>&1 &
17+
}
18+
19+
# Check if the settings file exists...
20+
if [ ! -f ~/.vscode-server/data/Machine/settings.json ]; then
21+
echo "⚙️ Creating settings file..."
22+
mkdir -p ~/.vscode-server/data/Machine
23+
echo "${SETTINGS}" > ~/.vscode-server/data/Machine/settings.json
24+
fi
25+
26+
# Check if vscode-server is already installed for offline or cached mode
27+
if [ -f "$VSCODE_WEB" ]; then
28+
if [ "${OFFLINE}" = true ] || [ "${USE_CACHED}" = true ]; then
29+
echo "🥳 Found a copy of VS Code Web"
30+
run_vscode_web
31+
exit 0
32+
fi
33+
fi
34+
# Offline mode always expects a copy of vscode-server to be present
35+
if [ "${OFFLINE}" = true ]; then
36+
echo "Failed to find a copy of VS Code Web"
37+
exit 1
38+
fi
39+
40+
# Create install prefix
41+
mkdir -p ${INSTALL_PREFIX}
42+
43+
printf "$${BOLD}Installing Microsoft Visual Studio Code Server!\n"
44+
45+
# Download and extract vscode-server
46+
ARCH=$(uname -m)
47+
case "$ARCH" in
48+
x86_64) ARCH="x64" ;;
49+
aarch64) ARCH="arm64" ;;
50+
*)
51+
echo "Unsupported architecture"
52+
exit 1
53+
;;
54+
esac
55+
56+
HASH=$(curl -fsSL https://update.code.visualstudio.com/api/commits/stable/server-linux-$ARCH-web | cut -d '"' -f 2)
57+
output=$(curl -fsSL https://vscode.download.prss.microsoft.com/dbazure/download/stable/$HASH/vscode-server-linux-$ARCH-web.tar.gz | tar -xz -C ${INSTALL_PREFIX} --strip-components 1)
58+
59+
if [ $? -ne 0 ]; then
60+
echo "Failed to install Microsoft Visual Studio Code Server: $output"
61+
exit 1
62+
fi
63+
printf "$${BOLD}VS Code Web has been installed.\n"
64+
65+
# Install each extension...
66+
IFS=',' read -r -a EXTENSIONLIST <<< "$${EXTENSIONS}"
67+
for extension in "$${EXTENSIONLIST[@]}"; do
68+
if [ -z "$extension" ]; then
69+
continue
70+
fi
71+
printf "🧩 Installing extension $${CODE}$extension$${RESET}...\n"
72+
output=$($VSCODE_WEB "$EXTENSION_ARG" --install-extension "$extension" --force)
73+
if [ $? -ne 0 ]; then
74+
echo "Failed to install extension: $extension: $output"
75+
exit 1
76+
fi
77+
done
78+
79+
if [ "${AUTO_INSTALL_EXTENSIONS}" = true ]; then
80+
if ! command -v jq > /dev/null; then
81+
echo "jq is required to install extensions from a workspace file."
82+
exit 0
83+
fi
84+
85+
WORKSPACE_DIR="$HOME"
86+
if [ -n "${FOLDER}" ]; then
87+
WORKSPACE_DIR="${FOLDER}"
88+
fi
89+
90+
if [ -f "$WORKSPACE_DIR/.vscode/extensions.json" ]; then
91+
printf "🧩 Installing extensions from %s/.vscode/extensions.json...\n" "$WORKSPACE_DIR"
92+
extensions=$(jq -r '.recommendations[]' "$WORKSPACE_DIR"/.vscode/extensions.json)
93+
for extension in $extensions; do
94+
$VSCODE_WEB "$EXTENSION_ARG" --install-extension "$extension" --force
95+
done
96+
fi
97+
fi
98+
99+
run_vscode_web
100+
101+
102+
# dotfiles, the same as dotfiles_run.sh
103+
DOTFILES_URI="${DOTFILES_URI}"
104+
DOTFILES_USER="${DOTFILES_USER}"
105+
106+
echo "Running install.sh..."
107+
108+
if [ -n "$${DOTFILES_URI// }" ]; then
109+
if [ -z "$DOTFILES_USER" ]; then
110+
DOTFILES_USER="$USER"
111+
fi
112+
113+
echo "✨ Applying dotfiles for user $DOTFILES_USER"
114+
115+
if [ "$DOTFILES_USER" = "$USER" ]; then
116+
coder dotfiles "$DOTFILES_URI" -y 2>&1 | tee ~/.dotfiles.log
117+
else
118+
# The `eval echo ~"$DOTFILES_USER"` part is used to dynamically get the home directory of the user, see https://superuser.com/a/484280
119+
# eval echo ~coder -> "/home/coder"
120+
# eval echo ~root -> "/root"
121+
122+
CODER_BIN=$(which coder)
123+
DOTFILES_USER_HOME=$(eval echo ~"$DOTFILES_USER")
124+
sudo -u "$DOTFILES_USER" sh -c "'$CODER_BIN' dotfiles '$DOTFILES_URI' -y 2>&1 | tee '$DOTFILES_USER_HOME'/.dotfiles.log"
125+
fi
126+
fi
127+
128+
echo "Dotfiles installation complete."

0 commit comments

Comments
 (0)