Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 45df4951b5 | |||
| f86c0c0742 | |||
| 18a8c7e8ee | |||
| 976691b5cb | |||
| f844c88c36 | |||
| 36089612ef | |||
| ac44ad862a | |||
| ef5a903edf | |||
| 4b7128b17e | |||
| 77a3e74e0b | |||
| 311de23454 | |||
| f66f61d724 | |||
| 631bf027c6 | |||
| eb4c28fc61 | |||
| c551c4d84a | |||
| 4b9da4036a | |||
| 96c5f3219d | |||
| 146540c1e9 |
@@ -1,14 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Version Bump Script
|
||||
# Usage: ./version-bump.sh <bump_type> [base_ref]
|
||||
# Usage: ./version-bump.sh [--ci] <bump_type> [base_ref]
|
||||
# --ci: CI mode - run bump, check for changes, exit 1 if changes needed
|
||||
# bump_type: patch, minor, or major
|
||||
# base_ref: base reference for diff (default: origin/main)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CI_MODE=false
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 <bump_type> [base_ref]"
|
||||
echo "Usage: $0 [--ci] <bump_type> [base_ref]"
|
||||
echo " --ci: CI mode - validates versions are already bumped (exits 1 if not)"
|
||||
echo " bump_type: patch, minor, or major"
|
||||
echo " base_ref: base reference for diff (default: origin/main)"
|
||||
echo ""
|
||||
@@ -16,6 +20,7 @@ usage() {
|
||||
echo " $0 patch # Update versions with patch bump"
|
||||
echo " $0 minor # Update versions with minor bump"
|
||||
echo " $0 major # Update versions with major bump"
|
||||
echo " $0 --ci patch # CI check: verify patch bump has been applied"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -85,7 +90,7 @@ update_readme_version() {
|
||||
in_module_block = 0
|
||||
if (module_has_target_source) {
|
||||
num_lines = split(module_content, lines, "\n")
|
||||
for (i = 1; i <= num_lines; i++) {
|
||||
for (i = 1; i < num_lines; i++) {
|
||||
line = lines[i]
|
||||
if (line ~ /^[[:space:]]*version[[:space:]]*=/) {
|
||||
match(line, /^[[:space:]]*/)
|
||||
@@ -115,6 +120,11 @@ update_readme_version() {
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "${1:-}" = "--ci" ]; then
|
||||
CI_MODE=true
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
|
||||
usage
|
||||
fi
|
||||
@@ -152,6 +162,8 @@ main() {
|
||||
local untagged_modules=""
|
||||
local has_changes=false
|
||||
|
||||
declare -a modified_readme_files=()
|
||||
|
||||
while IFS= read -r module_path; do
|
||||
if [ -z "$module_path" ]; then continue; fi
|
||||
|
||||
@@ -202,6 +214,7 @@ main() {
|
||||
|
||||
if update_readme_version "$readme_path" "$namespace" "$module_name" "$new_version"; then
|
||||
updated_readmes="$updated_readmes\n- $namespace/$module_name"
|
||||
modified_readme_files+=("$readme_path")
|
||||
has_changes=true
|
||||
fi
|
||||
|
||||
@@ -210,19 +223,22 @@ main() {
|
||||
|
||||
done <<< "$modules"
|
||||
|
||||
# Always run formatter to ensure consistent formatting
|
||||
echo "🔧 Running formatter to ensure consistent formatting..."
|
||||
if command -v bun > /dev/null 2>&1; then
|
||||
bun fmt > /dev/null 2>&1 || echo "⚠️ Warning: bun fmt failed, but continuing..."
|
||||
else
|
||||
echo "⚠️ Warning: bun not found, skipping formatting"
|
||||
if [ ${#modified_readme_files[@]} -gt 0 ]; then
|
||||
echo "🔧 Formatting modified README files..."
|
||||
if command -v bun > /dev/null 2>&1; then
|
||||
for readme_file in "${modified_readme_files[@]}"; do
|
||||
bun run prettier --write "$readme_file" 2> /dev/null || true
|
||||
done
|
||||
else
|
||||
echo "⚠️ Warning: bun not found, skipping formatting"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "📋 Summary:"
|
||||
echo "Bump Type: $bump_type"
|
||||
echo ""
|
||||
echo "Modules Updated:"
|
||||
echo "Modules Processed:"
|
||||
echo -e "$bumped_modules"
|
||||
echo ""
|
||||
|
||||
@@ -239,6 +255,19 @@ main() {
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "$CI_MODE" = true ]; then
|
||||
echo "🔍 Comparing files to committed versions..."
|
||||
if git diff --quiet; then
|
||||
echo "✅ PASS: All versions match - no changes needed"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ FAIL: Module versions need to be updated"
|
||||
echo ""
|
||||
echo "Run './.github/scripts/version-bump.sh $bump_type' locally and commit the changes"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$has_changes" = true ]; then
|
||||
echo "✅ Version bump completed successfully!"
|
||||
echo "📝 README files have been updated with new versions."
|
||||
|
||||
@@ -3,6 +3,7 @@ muc = "muc" # For Munich location code
|
||||
tyo = "tyo" # For Tokyo location code
|
||||
Hashi = "Hashi"
|
||||
HashiCorp = "HashiCorp"
|
||||
hel = "hel" # For Helsinki location code
|
||||
mavrickrishi = "mavrickrishi" # Username
|
||||
mavrick = "mavrick" # Username
|
||||
inh = "inh" # Option in setpriv command
|
||||
|
||||
@@ -55,62 +55,35 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Check version bump requirements
|
||||
id: version-check
|
||||
run: |
|
||||
output_file=$(mktemp)
|
||||
if ./.github/scripts/version-bump.sh "${{ steps.bump-type.outputs.type }}" origin/main > "$output_file" 2>&1; then
|
||||
echo "Script completed successfully"
|
||||
else
|
||||
echo "Script failed"
|
||||
cat "$output_file"
|
||||
exit 1
|
||||
fi
|
||||
- name: Check version bump
|
||||
run: ./.github/scripts/version-bump.sh --ci "${{ steps.bump-type.outputs.type }}" origin/main
|
||||
|
||||
{
|
||||
echo "output<<EOF"
|
||||
cat "$output_file"
|
||||
echo "EOF"
|
||||
} >> $GITHUB_OUTPUT
|
||||
|
||||
cat "$output_file"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "versions_up_to_date=true" >> $GITHUB_OUTPUT
|
||||
echo "✅ All module versions are already up to date"
|
||||
else
|
||||
echo "versions_up_to_date=false" >> $GITHUB_OUTPUT
|
||||
echo "❌ Module versions need to be updated"
|
||||
echo "Files that would be changed:"
|
||||
git diff --name-only
|
||||
echo ""
|
||||
echo "Diff preview:"
|
||||
git diff
|
||||
|
||||
git checkout .
|
||||
git clean -fd
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Comment on PR - Failure
|
||||
if: failure() && steps.version-check.outputs.versions_up_to_date == 'false'
|
||||
- name: Comment on PR - Version bump required
|
||||
if: failure()
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const output = `${{ steps.version-check.outputs.output }}`;
|
||||
const bumpType = `${{ steps.bump-type.outputs.type }}`;
|
||||
|
||||
let comment = `## ❌ Version Bump Validation Failed\n\n`;
|
||||
comment += `**Bump Type:** \`${bumpType}\`\n\n`;
|
||||
comment += `Module versions need to be updated but haven't been bumped yet.\n\n`;
|
||||
comment += `**Required Actions:**\n`;
|
||||
comment += `1. Run the version bump script locally: \`./.github/scripts/version-bump.sh ${bumpType}\`\n`;
|
||||
comment += `2. Commit the changes: \`git add . && git commit -m "chore: bump module versions (${bumpType})"\`\n`;
|
||||
comment += `3. Push the changes: \`git push\`\n\n`;
|
||||
comment += `### Script Output:\n\`\`\`\n${output}\n\`\`\`\n\n`;
|
||||
comment += `> Please update the module versions and push the changes to continue.`;
|
||||
const comment = [
|
||||
'## Version Bump Required',
|
||||
'',
|
||||
'One or more modules in this PR need their versions updated.',
|
||||
'',
|
||||
'**To fix this:**',
|
||||
'1. Run the version bump script locally:',
|
||||
' ```bash',
|
||||
` ./.github/scripts/version-bump.sh ${bumpType}`,
|
||||
' ```',
|
||||
'2. Commit the changes:',
|
||||
' ```bash',
|
||||
` git add . && git commit -m "chore: bump module versions (${bumpType})"`,
|
||||
' ```',
|
||||
'3. Push your changes',
|
||||
'',
|
||||
'The CI will automatically re-run once you push the updated versions.'
|
||||
].join('\n');
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="128" cy="128" r="120" fill="black"/>
|
||||
<polygon
|
||||
points="128,70 178,170 78,170"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 216 B |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 451 KiB After Width: | Height: | Size: 451 KiB |
|
After Width: | Height: | Size: 98 KiB |
@@ -0,0 +1,7 @@
|
||||
---
|
||||
display_name: "Excellencedev"
|
||||
bio: "Love to contribute"
|
||||
avatar: "./.images/avatar.png"
|
||||
support_email: "ademiluyisuccessandexcellence@gmail.com"
|
||||
status: "community"
|
||||
---
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
display_name: Hetzner Cloud Server
|
||||
description: Provision Hetzner Cloud servers as Coder workspaces
|
||||
icon: ../../../../.icons/hetzner.svg
|
||||
tags: [vm, linux, hetzner]
|
||||
---
|
||||
|
||||
# Remote Development on Hetzner Cloud (Linux)
|
||||
|
||||
Provision Hetzner Cloud servers as [Coder workspaces](https://coder.com/docs/workspaces) with this example template.
|
||||
|
||||
> [!WARNING]
|
||||
> **Workspace Storage Persistence:** When a workspace is stopped, the Hetzner Cloud server instance is stopped but your home volume and stored data persist. This means your files and data remain intact when you resume the workspace.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Volume Management & Costs:** Hetzner Cloud volumes persist even when workspaces are stopped and will continue to incur storage costs (€0.0476/GB/month). Volumes are only automatically deleted when the workspace is completely deleted. Monitor your volumes in the [Hetzner Cloud Console](https://console.hetzner.cloud/) to manage costs effectively.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To deploy workspaces as Hetzner Cloud servers, you'll need:
|
||||
|
||||
- Hetzner Cloud [API token](https://console.hetzner.cloud/projects) (create under Security > API Tokens)
|
||||
|
||||
### Authentication
|
||||
|
||||
This template assumes that the Coder Provisioner is run in an environment that is authenticated with Hetzner Cloud.
|
||||
|
||||
Obtain a Hetzner Cloud API token from your [Hetzner Cloud Console](https://console.hetzner.cloud/projects) and provide it as the `hcloud_token` variable when creating a workspace.
|
||||
For more authentication options, see the [Terraform provider documentation](https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs#authentication).
|
||||
|
||||
> [!NOTE]
|
||||
> This template is designed to be a starting point. Edit the Terraform to extend the template to support your use case.
|
||||
@@ -0,0 +1,62 @@
|
||||
#cloud-config
|
||||
users:
|
||||
- name: ${username}
|
||||
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||
groups: sudo
|
||||
shell: /bin/bash
|
||||
packages:
|
||||
- git
|
||||
%{ if home_volume_label != "" ~}
|
||||
fs_setup:
|
||||
- device: /dev/disk/by-id/scsi-0HC_Volume_${volume_id}
|
||||
filesystem: ext4
|
||||
label: ${home_volume_label}
|
||||
overwrite: false # This prevents reformatting the disk on every boot
|
||||
|
||||
mounts:
|
||||
- [
|
||||
"/dev/disk/by-id/scsi-0HC_Volume_${volume_id}",
|
||||
"/home/${username}",
|
||||
ext4,
|
||||
"defaults,uid=1000,gid=1000",
|
||||
]
|
||||
%{ endif ~}
|
||||
write_files:
|
||||
- path: /opt/coder/init
|
||||
permissions: "0755"
|
||||
encoding: b64
|
||||
content: ${init_script}
|
||||
- path: /etc/systemd/system/coder-agent.service
|
||||
permissions: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Coder Agent
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
User=${username}
|
||||
ExecStart=/opt/coder/init
|
||||
Environment=CODER_AGENT_TOKEN=${coder_agent_token}
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
TimeoutStopSec=90
|
||||
KillMode=process
|
||||
|
||||
OOMScoreAdjust=-900
|
||||
SyslogIdentifier=coder-agent
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
runcmd:
|
||||
%{ if home_volume_label != "" ~}
|
||||
- |
|
||||
until [ -e /dev/disk/by-id/scsi-0HC_Volume_${volume_id} ]; do
|
||||
echo "Waiting for volume device..."
|
||||
sleep 2
|
||||
done
|
||||
%{ endif ~}
|
||||
- mount -a
|
||||
- chown ${username}:${username} /home/${username}
|
||||
- systemctl enable coder-agent
|
||||
- systemctl start coder-agent
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type_meta": {
|
||||
"cx22": { "cores": 2, "memory_gb": 4, "disk_gb": 40 },
|
||||
"cx32": { "cores": 4, "memory_gb": 8, "disk_gb": 80 },
|
||||
"cx42": { "cores": 8, "memory_gb": 16, "disk_gb": 160 },
|
||||
"cx52": { "cores": 16, "memory_gb": 32, "disk_gb": 320 },
|
||||
"cpx11": { "cores": 2, "memory_gb": 2, "disk_gb": 40 },
|
||||
"cpx21": { "cores": 3, "memory_gb": 4, "disk_gb": 80 },
|
||||
"cpx31": { "cores": 4, "memory_gb": 8, "disk_gb": 160 },
|
||||
"cpx41": { "cores": 8, "memory_gb": 16, "disk_gb": 240 },
|
||||
"cpx51": { "cores": 16, "memory_gb": 32, "disk_gb": 360 },
|
||||
"ccx13": { "cores": 2, "memory_gb": 8, "disk_gb": 80 },
|
||||
"ccx23": { "cores": 4, "memory_gb": 16, "disk_gb": 160 },
|
||||
"ccx33": { "cores": 8, "memory_gb": 32, "disk_gb": 240 },
|
||||
"ccx43": { "cores": 16, "memory_gb": 64, "disk_gb": 360 },
|
||||
"ccx53": { "cores": 32, "memory_gb": 128, "disk_gb": 600 },
|
||||
"ccx63": { "cores": 48, "memory_gb": 192, "disk_gb": 960 }
|
||||
},
|
||||
"availability": {
|
||||
"fsn1": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
|
||||
"ash": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
|
||||
"hel1": ["cx22", "cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
|
||||
"hil": ["cpx11", "cpx21", "cpx31", "cpx41", "ccx13", "ccx23", "ccx33"],
|
||||
"nbg1": ["cx22", "cx32", "cx42", "cx52", "cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
|
||||
"sin": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
hcloud = {
|
||||
source = "hetznercloud/hcloud"
|
||||
}
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "hcloud_token" {
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
provider "hcloud" {
|
||||
token = var.hcloud_token
|
||||
}
|
||||
|
||||
# Available locations: https://docs.hetzner.com/cloud/general/locations/
|
||||
data "coder_parameter" "hcloud_location" {
|
||||
name = "hcloud_location"
|
||||
display_name = "Hetzner Location"
|
||||
description = "Select the Hetzner Cloud location for your workspace."
|
||||
type = "string"
|
||||
default = "fsn1"
|
||||
option {
|
||||
name = "DE Falkenstein"
|
||||
value = "fsn1"
|
||||
}
|
||||
option {
|
||||
name = "US Ashburn, VA"
|
||||
value = "ash"
|
||||
}
|
||||
option {
|
||||
name = "US Hillsboro, OR"
|
||||
value = "hil"
|
||||
}
|
||||
option {
|
||||
name = "SG Singapore"
|
||||
value = "sin"
|
||||
}
|
||||
option {
|
||||
name = "DE Nuremberg"
|
||||
value = "nbg1"
|
||||
}
|
||||
option {
|
||||
name = "FI Helsinki"
|
||||
value = "hel1"
|
||||
}
|
||||
}
|
||||
|
||||
# Available server types: https://docs.hetzner.com/cloud/servers/overview/
|
||||
data "coder_parameter" "hcloud_server_type" {
|
||||
name = "hcloud_server_type"
|
||||
display_name = "Hetzner Server Type"
|
||||
description = "Select the Hetzner Cloud server type for your workspace."
|
||||
type = "string"
|
||||
|
||||
dynamic "option" {
|
||||
for_each = local.hcloud_server_type_options_for_selected_location
|
||||
content {
|
||||
name = option.value.name
|
||||
value = option.value.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "hcloud_server" "dev" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
name = "coder-${data.coder_workspace.me.name}-dev"
|
||||
image = "ubuntu-24.04"
|
||||
server_type = data.coder_parameter.hcloud_server_type.value
|
||||
location = data.coder_parameter.hcloud_location.value
|
||||
public_net {
|
||||
ipv4_enabled = true
|
||||
ipv6_enabled = true
|
||||
}
|
||||
user_data = templatefile("cloud-config.yaml.tftpl", {
|
||||
username = lower(data.coder_workspace_owner.me.name)
|
||||
home_volume_label = "coder-${data.coder_workspace.me.id}-home"
|
||||
volume_id = hcloud_volume.home_volume.id
|
||||
init_script = base64encode(coder_agent.main.init_script)
|
||||
coder_agent_token = coder_agent.main.token
|
||||
})
|
||||
labels = {
|
||||
"coder_workspace_name" = data.coder_workspace.me.name,
|
||||
"coder_workspace_owner" = data.coder_workspace_owner.me.name,
|
||||
}
|
||||
}
|
||||
|
||||
resource "hcloud_volume" "home_volume" {
|
||||
name = "coder-${data.coder_workspace.me.id}-home"
|
||||
size = data.coder_parameter.home_volume_size.value
|
||||
location = data.coder_parameter.hcloud_location.value
|
||||
labels = {
|
||||
"coder_workspace_name" = data.coder_workspace.me.name,
|
||||
"coder_workspace_owner" = data.coder_workspace_owner.me.name,
|
||||
}
|
||||
}
|
||||
|
||||
resource "hcloud_volume_attachment" "home_volume_attachment" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
volume_id = hcloud_volume.home_volume.id
|
||||
server_id = hcloud_server.dev[count.index].id
|
||||
automount = false
|
||||
}
|
||||
|
||||
locals {
|
||||
username = lower(data.coder_workspace_owner.me.name)
|
||||
|
||||
# Data source: local JSON file under the module directory
|
||||
# Check API for latest server types & availability: https://docs.hetzner.cloud/reference/cloud#server-types
|
||||
hcloud_server_types_data = jsondecode(file("${path.module}/hetzner_server_types.json"))
|
||||
hcloud_server_type_meta = local.hcloud_server_types_data.type_meta
|
||||
hcloud_server_types_by_location = local.hcloud_server_types_data.availability
|
||||
|
||||
hcloud_server_type_options_for_selected_location = [
|
||||
for type_name in lookup(local.hcloud_server_types_by_location, data.coder_parameter.hcloud_location.value, []) : {
|
||||
name = format("%s (%d vCPU, %dGB RAM, %dGB)", upper(type_name), local.hcloud_server_type_meta[type_name].cores, local.hcloud_server_type_meta[type_name].memory_gb, local.hcloud_server_type_meta[type_name].disk_gb)
|
||||
value = type_name
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
|
||||
provider "coder" {}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
data "coder_parameter" "home_volume_size" {
|
||||
name = "home_volume_size"
|
||||
display_name = "Home volume size"
|
||||
description = "How large would you like your home volume to be (in GB)?"
|
||||
type = "number"
|
||||
default = "20"
|
||||
mutable = false
|
||||
validation {
|
||||
min = 1
|
||||
max = 100 # Adjust the max size as needed
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
|
||||
metadata {
|
||||
key = "cpu"
|
||||
display_name = "CPU Usage"
|
||||
interval = 5
|
||||
timeout = 5
|
||||
script = "coder stat cpu"
|
||||
}
|
||||
metadata {
|
||||
key = "memory"
|
||||
display_name = "Memory Usage"
|
||||
interval = 5
|
||||
timeout = 5
|
||||
script = "coder stat mem"
|
||||
}
|
||||
metadata {
|
||||
key = "home"
|
||||
display_name = "Home Usage"
|
||||
interval = 600 # every 10 minutes
|
||||
timeout = 30 # df can take a while on large filesystems
|
||||
script = "coder stat disk --path /home/${local.username}"
|
||||
}
|
||||
}
|
||||
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
|
||||
# This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
|
||||
version = "~> 1.0"
|
||||
|
||||
agent_id = coder_agent.main.id
|
||||
order = 1
|
||||
}
|
||||
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 240 KiB |
|
After Width: | Height: | Size: 590 KiB |
@@ -13,7 +13,7 @@ Run Auggie CLI in your workspace to access Augment's AI coding assistant with ad
|
||||
```tf
|
||||
module "auggie" {
|
||||
source = "registry.coder.com/coder-labs/auggie/coder"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder/project"
|
||||
}
|
||||
@@ -47,7 +47,7 @@ module "coder-login" {
|
||||
|
||||
module "auggie" {
|
||||
source = "registry.coder.com/coder-labs/auggie/coder"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder/project"
|
||||
|
||||
@@ -103,7 +103,7 @@ EOF
|
||||
```tf
|
||||
module "auggie" {
|
||||
source = "registry.coder.com/coder-labs/auggie/coder"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder/project"
|
||||
|
||||
@@ -133,6 +133,35 @@ EOF
|
||||
}
|
||||
```
|
||||
|
||||
### Using the task_app_id Output
|
||||
|
||||
```tf
|
||||
module "auggie" {
|
||||
source = "registry.coder.com/coder-labs/auggie/coder"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder/project"
|
||||
|
||||
augment_session_token = <<-EOF
|
||||
{"accessToken":"xxxx-yyyy-zzzz-jjjj","tenantURL":"https://d1.api.augmentcode.com/","scopes":["read","write"]}
|
||||
EOF
|
||||
|
||||
report_tasks = true
|
||||
}
|
||||
|
||||
# Expose the task app ID as a template output
|
||||
output "auggie_task_app_id" {
|
||||
value = module.auggie.task_app_id
|
||||
description = "The ID of the Auggie AgentAPI web app for task reporting"
|
||||
}
|
||||
```
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| `task_app_id` | The ID of the AgentAPI web app, which can be used to reference the app in other resources or for task reporting integration |
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you have any issues, please take a look at the log files below.
|
||||
|
||||
@@ -4,7 +4,7 @@ terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.7"
|
||||
version = ">= 2.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ variable "auggie_model" {
|
||||
variable "report_tasks" {
|
||||
type = bool
|
||||
description = "Whether to enable task reporting to Coder UI via AgentAPI"
|
||||
default = false
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "cli_app" {
|
||||
@@ -179,7 +179,7 @@ locals {
|
||||
|
||||
module "agentapi" {
|
||||
source = "registry.coder.com/coder/agentapi/coder"
|
||||
version = "1.2.0"
|
||||
version = "2.0.0"
|
||||
|
||||
agent_id = var.agent_id
|
||||
folder = local.folder
|
||||
@@ -229,4 +229,8 @@ module "agentapi" {
|
||||
ARG_MCP_CONFIG='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \
|
||||
/tmp/install.sh
|
||||
EOT
|
||||
}
|
||||
}
|
||||
|
||||
output "task_app_id" {
|
||||
value = module.agentapi.task_app_id
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
source "$HOME"/.bashrc
|
||||
fi
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BOLD='\033[0;1m'
|
||||
@@ -13,6 +9,12 @@ command_exists() {
|
||||
command -v "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
if [ -f "$HOME/.nvm/nvm.sh" ]; then
|
||||
source "$HOME"/.nvm/nvm.sh
|
||||
else
|
||||
export PATH="$HOME/.npm-global/bin:$PATH"
|
||||
fi
|
||||
|
||||
ARG_AUGGIE_INSTALL=${ARG_AUGGIE_INSTALL:-true}
|
||||
ARG_AUGGIE_VERSION=${ARG_AUGGIE_VERSION:-}
|
||||
ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-}
|
||||
@@ -29,6 +31,13 @@ printf "rules: %s\n" "$ARG_AUGGIE_RULES"
|
||||
echo "--------------------------------"
|
||||
|
||||
function check_dependencies() {
|
||||
|
||||
printf "PATH: %s\n" "${PATH}"
|
||||
|
||||
new_path=$(bash -l -c 'echo $PATH' 2>/dev/null || echo "${PATH}")
|
||||
|
||||
printf "NEW_PATH %s\n" "${new_path}"
|
||||
|
||||
if ! command_exists node; then
|
||||
printf "Error: Node.js is not installed. Please install Node.js manually or use the pre_install_script to install it.\n"
|
||||
exit 1
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
source "$HOME"/.bashrc
|
||||
fi
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
command_exists() {
|
||||
|
||||
@@ -13,7 +13,7 @@ Run [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-c
|
||||
```tf
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
}
|
||||
@@ -51,7 +51,7 @@ data "coder_parameter" "ai_prompt" {
|
||||
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
|
||||
@@ -71,7 +71,7 @@ Customize tool permissions, MCP servers, and Copilot settings:
|
||||
```tf
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
|
||||
@@ -142,7 +142,7 @@ variable "github_token" {
|
||||
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
github_token = var.github_token
|
||||
@@ -156,7 +156,7 @@ Run Copilot as a command-line tool without task reporting or web interface. This
|
||||
```tf
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder"
|
||||
report_tasks = false
|
||||
|
||||
@@ -3,7 +3,7 @@ terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.7"
|
||||
version = ">= 2.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ resource "coder_env" "github_token" {
|
||||
|
||||
module "agentapi" {
|
||||
source = "registry.coder.com/coder/agentapi/coder"
|
||||
version = "1.2.0"
|
||||
version = "2.0.0"
|
||||
|
||||
agent_id = var.agent_id
|
||||
folder = local.workdir
|
||||
@@ -268,7 +268,7 @@ module "agentapi" {
|
||||
set -o pipefail
|
||||
echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
|
||||
chmod +x /tmp/start.sh
|
||||
|
||||
|
||||
ARG_WORKDIR='${local.workdir}' \
|
||||
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
|
||||
ARG_SYSTEM_PROMPT='${base64encode(local.final_system_prompt)}' \
|
||||
@@ -288,7 +288,7 @@ module "agentapi" {
|
||||
set -o pipefail
|
||||
echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
|
||||
chmod +x /tmp/install.sh
|
||||
|
||||
|
||||
ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \
|
||||
ARG_REPORT_TASKS='${var.report_tasks}' \
|
||||
ARG_WORKDIR='${local.workdir}' \
|
||||
@@ -299,4 +299,8 @@ module "agentapi" {
|
||||
ARG_COPILOT_MODEL='${var.copilot_model}' \
|
||||
/tmp/install.sh
|
||||
EOT
|
||||
}
|
||||
}
|
||||
|
||||
output "task_app_id" {
|
||||
value = module.agentapi.task_app_id
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ Run the Cursor Agent CLI in your workspace for interactive coding assistance and
|
||||
```tf
|
||||
module "cursor_cli" {
|
||||
source = "registry.coder.com/coder-labs/cursor-cli/coder"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder/project"
|
||||
}
|
||||
@@ -42,7 +42,7 @@ module "coder-login" {
|
||||
|
||||
module "cursor_cli" {
|
||||
source = "registry.coder.com/coder-labs/cursor-cli/coder"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder/project"
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ describe("cursor-cli", async () => {
|
||||
"-c",
|
||||
"cat /home/coder/.cursor-cli-module/agentapi-start.log || cat /home/coder/.cursor-cli-module/start.log || true",
|
||||
]);
|
||||
expect(startLog.stdout).toContain(`-m ${model}`);
|
||||
expect(startLog.stdout).toContain(`--model ${model}`);
|
||||
expect(startLog.stdout).toContain("-f");
|
||||
expect(startLog.stdout).toContain("test prompt");
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.7"
|
||||
version = ">= 2.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ resource "coder_env" "cursor_api_key" {
|
||||
|
||||
module "agentapi" {
|
||||
source = "registry.coder.com/coder/agentapi/coder"
|
||||
version = "1.2.0"
|
||||
version = "2.0.0"
|
||||
|
||||
agent_id = var.agent_id
|
||||
folder = local.folder
|
||||
@@ -179,3 +179,7 @@ module "agentapi" {
|
||||
/tmp/install.sh
|
||||
EOT
|
||||
}
|
||||
|
||||
output "task_app_id" {
|
||||
value = module.agentapi.task_app_id
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ ARGS=()
|
||||
|
||||
# global flags
|
||||
if [ -n "$ARG_MODEL" ]; then
|
||||
ARGS+=("-m" "$ARG_MODEL")
|
||||
ARGS+=("--model" "$ARG_MODEL")
|
||||
fi
|
||||
if [ "$ARG_FORCE" = "true" ]; then
|
||||
ARGS+=("-f")
|
||||
|
||||
@@ -13,7 +13,7 @@ Run [Gemini CLI](https://github.com/google-gemini/gemini-cli) in your workspace
|
||||
```tf
|
||||
module "gemini" {
|
||||
source = "registry.coder.com/coder-labs/gemini/coder"
|
||||
version = "2.1.2"
|
||||
version = "3.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder/project"
|
||||
}
|
||||
@@ -46,7 +46,7 @@ variable "gemini_api_key" {
|
||||
|
||||
module "gemini" {
|
||||
source = "registry.coder.com/coder-labs/gemini/coder"
|
||||
version = "2.1.2"
|
||||
version = "3.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
gemini_api_key = var.gemini_api_key
|
||||
folder = "/home/coder/project"
|
||||
@@ -94,7 +94,7 @@ data "coder_parameter" "ai_prompt" {
|
||||
module "gemini" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder-labs/gemini/coder"
|
||||
version = "2.1.2"
|
||||
version = "3.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
gemini_api_key = var.gemini_api_key
|
||||
gemini_model = "gemini-2.5-flash"
|
||||
@@ -118,7 +118,7 @@ For enterprise users who prefer Google's Vertex AI platform:
|
||||
```tf
|
||||
module "gemini" {
|
||||
source = "registry.coder.com/coder-labs/gemini/coder"
|
||||
version = "2.1.2"
|
||||
version = "3.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
gemini_api_key = var.gemini_api_key
|
||||
folder = "/home/coder/project"
|
||||
|
||||
@@ -4,7 +4,7 @@ terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.7"
|
||||
version = ">= 2.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ EOT
|
||||
|
||||
module "agentapi" {
|
||||
source = "registry.coder.com/coder/agentapi/coder"
|
||||
version = "1.2.0"
|
||||
version = "2.0.0"
|
||||
|
||||
agent_id = var.agent_id
|
||||
folder = local.folder
|
||||
@@ -225,4 +225,8 @@ module "agentapi" {
|
||||
GEMINI_TASK_PROMPT='${var.task_prompt}' \
|
||||
/tmp/start.sh
|
||||
EOT
|
||||
}
|
||||
}
|
||||
|
||||
output "task_app_id" {
|
||||
value = module.agentapi.task_app_id
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
display_name: Perplexica
|
||||
description: Run Perplexica AI search engine in your workspace via Docker
|
||||
icon: ../../../../.icons/perplexica.svg
|
||||
verified: false
|
||||
tags: [ai, search, docker]
|
||||
---
|
||||
|
||||
# Perplexica
|
||||
|
||||
Run [Perplexica](https://github.com/ItzCrazyKns/Perplexica), a privacy-focused AI search engine, in your Coder workspace. Supports cloud providers (OpenAI, Anthropic Claude) and local LLMs via Ollama.
|
||||
|
||||
```tf
|
||||
module "perplexica" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder-labs/perplexica/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
|
||||
This module uses the full Perplexica image with embedded SearXNG for simpler setup with no external dependencies.
|
||||
|
||||

|
||||
|
||||
## Prerequisites
|
||||
|
||||
This module requires Docker to be available on the host.
|
||||
|
||||
## Examples
|
||||
|
||||
### With API Keys
|
||||
|
||||
```tf
|
||||
module "perplexica" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder-labs/perplexica/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
openai_api_key = var.openai_api_key
|
||||
anthropic_api_key = var.anthropic_api_key
|
||||
}
|
||||
```
|
||||
|
||||
### With Local Ollama
|
||||
|
||||
```tf
|
||||
module "perplexica" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder-labs/perplexica/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
ollama_api_url = "http://ollama-external-endpoint:11434"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,108 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "agent_id" {
|
||||
type = string
|
||||
description = "The ID of a Coder agent."
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
type = string
|
||||
description = "(Optional) Docker socket URI"
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "port" {
|
||||
type = number
|
||||
description = "The port to run Perplexica on."
|
||||
default = 3000
|
||||
}
|
||||
|
||||
variable "data_path" {
|
||||
type = string
|
||||
description = "Host path to mount for Perplexica data persistence."
|
||||
default = "./perplexica-data"
|
||||
}
|
||||
|
||||
variable "uploads_path" {
|
||||
type = string
|
||||
description = "Host path to mount for Perplexica file uploads."
|
||||
default = "./perplexica-uploads"
|
||||
}
|
||||
|
||||
variable "openai_api_key" {
|
||||
type = string
|
||||
description = "OpenAI API key."
|
||||
default = ""
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "anthropic_api_key" {
|
||||
type = string
|
||||
description = "Anthropic API key for Claude models."
|
||||
default = ""
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "ollama_api_url" {
|
||||
type = string
|
||||
description = "Ollama API URL for local LLM support."
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "share" {
|
||||
type = string
|
||||
default = "owner"
|
||||
validation {
|
||||
condition = var.share == "owner" || var.share == "authenticated" || var.share == "public"
|
||||
error_message = "Incorrect value. Please set either 'owner', 'authenticated', or 'public'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "order" {
|
||||
type = number
|
||||
description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "group" {
|
||||
type = string
|
||||
description = "The name of a group that this app belongs to."
|
||||
default = null
|
||||
}
|
||||
|
||||
resource "coder_script" "perplexica" {
|
||||
agent_id = var.agent_id
|
||||
display_name = "Perplexica"
|
||||
icon = "/icon/perplexica.svg"
|
||||
script = templatefile("${path.module}/run.sh", {
|
||||
DOCKER_HOST : var.docker_socket,
|
||||
PORT : var.port,
|
||||
DATA_PATH : var.data_path,
|
||||
UPLOADS_PATH : var.uploads_path,
|
||||
OPENAI_API_KEY : var.openai_api_key,
|
||||
ANTHROPIC_API_KEY : var.anthropic_api_key,
|
||||
OLLAMA_API_URL : var.ollama_api_url,
|
||||
})
|
||||
run_on_start = true
|
||||
}
|
||||
|
||||
resource "coder_app" "perplexica" {
|
||||
agent_id = var.agent_id
|
||||
slug = "perplexica"
|
||||
display_name = "Perplexica"
|
||||
url = "http://localhost:${var.port}"
|
||||
icon = "/icon/perplexica.svg"
|
||||
subdomain = true
|
||||
share = var.share
|
||||
order = var.order
|
||||
group = var.group
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
run "plan_basic" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = resource.coder_app.perplexica.url == "http://localhost:3000"
|
||||
error_message = "Default port should be 3000"
|
||||
}
|
||||
}
|
||||
|
||||
run "plan_custom_port" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent"
|
||||
port = 8080
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = resource.coder_app.perplexica.url == "http://localhost:8080"
|
||||
error_message = "Should use custom port"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -eu
|
||||
|
||||
BOLD='\033[0;1m'
|
||||
RESET='\033[0m'
|
||||
|
||||
printf "$${BOLD}Starting Perplexica...$${RESET}\n"
|
||||
|
||||
# Set Docker host if provided
|
||||
if [ -n "${DOCKER_HOST}" ]; then
|
||||
export DOCKER_HOST="${DOCKER_HOST}"
|
||||
fi
|
||||
|
||||
# Wait for docker to become ready
|
||||
max_attempts=10
|
||||
delay=2
|
||||
attempt=1
|
||||
|
||||
while ! docker ps; do
|
||||
if [ $attempt -ge $max_attempts ]; then
|
||||
echo "Failed to list containers after $${max_attempts} attempts."
|
||||
exit 1
|
||||
fi
|
||||
echo "Attempt $${attempt} failed, retrying in $${delay}s..."
|
||||
sleep $delay
|
||||
attempt=$(expr "$attempt" + 1)
|
||||
delay=$(expr "$delay" \* 2)
|
||||
done
|
||||
|
||||
# Pull the image
|
||||
IMAGE="itzcrazykns1337/perplexica:latest"
|
||||
docker pull "$${IMAGE}"
|
||||
|
||||
# Build docker run command
|
||||
DOCKER_ARGS="-d --rm --name perplexica -p ${PORT}:3000"
|
||||
|
||||
# Add mounts - convert relative paths to absolute
|
||||
DATA_PATH="${DATA_PATH}"
|
||||
UPLOADS_PATH="${UPLOADS_PATH}"
|
||||
|
||||
mkdir -p "$${DATA_PATH}"
|
||||
mkdir -p "$${UPLOADS_PATH}"
|
||||
|
||||
DATA_PATH_ABS=$(cd "$${DATA_PATH}" && pwd)
|
||||
UPLOADS_PATH_ABS=$(cd "$${UPLOADS_PATH}" && pwd)
|
||||
|
||||
DOCKER_ARGS="$${DOCKER_ARGS} -v $${DATA_PATH_ABS}:/home/perplexica/data"
|
||||
DOCKER_ARGS="$${DOCKER_ARGS} -v $${UPLOADS_PATH_ABS}:/home/perplexica/uploads"
|
||||
|
||||
# Add environment variables if provided
|
||||
if [ -n "${OPENAI_API_KEY}" ]; then
|
||||
DOCKER_ARGS="$${DOCKER_ARGS} -e OPENAI_API_KEY=${OPENAI_API_KEY}"
|
||||
fi
|
||||
|
||||
if [ -n "${ANTHROPIC_API_KEY}" ]; then
|
||||
DOCKER_ARGS="$${DOCKER_ARGS} -e ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}"
|
||||
fi
|
||||
|
||||
if [ -n "${OLLAMA_API_URL}" ]; then
|
||||
DOCKER_ARGS="$${DOCKER_ARGS} -e OLLAMA_API_URL=${OLLAMA_API_URL}"
|
||||
fi
|
||||
|
||||
# Run container
|
||||
docker run $${DOCKER_ARGS} "$${IMAGE}"
|
||||
|
||||
printf "\n$${BOLD}Perplexica is running on port ${PORT}$${RESET}\n"
|
||||
@@ -13,7 +13,7 @@ Run [Amp CLI](https://ampcode.com/) in your workspace to access Sourcegraph's AI
|
||||
```tf
|
||||
module "amp-cli" {
|
||||
source = "registry.coder.com/coder-labs/sourcegraph-amp/coder"
|
||||
version = "2.1.0"
|
||||
version = "3.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
amp_api_key = var.amp_api_key
|
||||
install_amp = true
|
||||
@@ -48,7 +48,7 @@ variable "amp_api_key" {
|
||||
module "amp-cli" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder-labs/sourcegraph-amp/coder"
|
||||
amp_version = "2.1.0"
|
||||
amp_version = "3.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
amp_api_key = var.amp_api_key # recommended for tasks usage
|
||||
workdir = "/home/coder/project"
|
||||
|
||||
@@ -110,6 +110,7 @@ describe("amp", async () => {
|
||||
const { id } = await setup({
|
||||
skipAmpMock: true,
|
||||
moduleVariables: {
|
||||
install_via_npm: "true",
|
||||
amp_version: "0.0.1755964909-g31e083",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.7"
|
||||
version = ">= 2.12"
|
||||
}
|
||||
external = {
|
||||
source = "hashicorp/external"
|
||||
@@ -140,7 +140,7 @@ variable "base_amp_config" {
|
||||
type = string
|
||||
description = <<-EOT
|
||||
Base AMP configuration in JSON format. Can be overridden to customize AMP settings.
|
||||
|
||||
|
||||
If empty, defaults enable thinking and todos for autonomous operation. Additional options include:
|
||||
- "amp.permissions": [] (tool permissions)
|
||||
- "amp.tools.stopTimeout": 600 (extend timeout for long operations)
|
||||
@@ -148,7 +148,7 @@ variable "base_amp_config" {
|
||||
- "amp.tools.disable": ["builtin:open"] (disable tools for containers)
|
||||
- "amp.git.commit.ampThread.enabled": true (link commits to threads)
|
||||
- "amp.git.commit.coauthor.enabled": true (add Amp as co-author)
|
||||
|
||||
|
||||
Reference: https://ampcode.com/manual
|
||||
EOT
|
||||
default = ""
|
||||
@@ -220,7 +220,7 @@ locals {
|
||||
|
||||
module "agentapi" {
|
||||
source = "registry.coder.com/coder/agentapi/coder"
|
||||
version = "1.2.0"
|
||||
version = "2.0.0"
|
||||
|
||||
agent_id = var.agent_id
|
||||
folder = local.workdir
|
||||
@@ -268,4 +268,6 @@ module "agentapi" {
|
||||
EOT
|
||||
}
|
||||
|
||||
|
||||
output "task_app_id" {
|
||||
value = module.agentapi.task_app_id
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 976 KiB After Width: | Height: | Size: 528 KiB |
|
Before Width: | Height: | Size: 302 KiB After Width: | Height: | Size: 191 KiB |
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
|
||||
```tf
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
claude_api_key = "xxxx-xxxxx-xxxx"
|
||||
@@ -45,7 +45,7 @@ This example shows how to configure the Claude Code module to run the agent behi
|
||||
```tf
|
||||
module "claude-code" {
|
||||
source = "dev.registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
enable_boundary = true
|
||||
@@ -72,7 +72,7 @@ data "coder_parameter" "ai_prompt" {
|
||||
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
|
||||
@@ -108,7 +108,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
|
||||
```tf
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
install_claude_code = true
|
||||
@@ -130,7 +130,7 @@ variable "claude_code_oauth_token" {
|
||||
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
claude_code_oauth_token = var.claude_code_oauth_token
|
||||
@@ -203,7 +203,7 @@ resource "coder_env" "bedrock_api_key" {
|
||||
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
|
||||
@@ -260,7 +260,7 @@ resource "coder_env" "google_application_credentials" {
|
||||
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.2.7"
|
||||
version = "4.2.8"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
model = "claude-sonnet-4@20250514"
|
||||
|
||||
@@ -86,7 +86,7 @@ variable "install_agentapi" {
|
||||
variable "agentapi_version" {
|
||||
type = string
|
||||
description = "The version of AgentAPI to install."
|
||||
default = "v0.11.4"
|
||||
default = "v0.11.6"
|
||||
}
|
||||
|
||||
variable "ai_prompt" {
|
||||
|
||||
@@ -14,7 +14,7 @@ Automatically install [code-server](https://github.com/coder/code-server) in a w
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
}
|
||||
```
|
||||
@@ -29,9 +29,9 @@ module "code-server" {
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
install_version = "1.4.1"
|
||||
install_version = "4.106.3"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -43,7 +43,7 @@ Install the Dracula theme from [OpenVSX](https://open-vsx.org/):
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
extensions = [
|
||||
"dracula-theme.theme-dracula"
|
||||
@@ -61,7 +61,7 @@ Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarte
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
extensions = ["dracula-theme.theme-dracula"]
|
||||
settings = {
|
||||
@@ -78,7 +78,7 @@ Just run code-server in the background, don't fetch it from GitHub:
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
|
||||
}
|
||||
@@ -92,7 +92,7 @@ You can pass additional command-line arguments to code-server using the `additio
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
additional_args = "--disable-workspace-trust"
|
||||
}
|
||||
@@ -108,7 +108,7 @@ Run an existing copy of code-server if found, otherwise download from GitHub:
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
use_cached = true
|
||||
extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"]
|
||||
@@ -121,8 +121,10 @@ Just run code-server in the background, don't fetch it from GitHub:
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.example.id
|
||||
offline = true
|
||||
}
|
||||
```
|
||||
|
||||
Some of the key differences between code-server and [VS Code Web](https://registry.coder.com/modules/coder/vscode-web) are listed in [docs](https://coder.com/docs/user-guides/workspace-access/code-server#differences-between-code-server-and-vs-code-web).
|
||||
|
||||
@@ -19,7 +19,7 @@ Zed is a high-performance, multiplayer code editor from the creators of Atom and
|
||||
module "zed" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/zed/coder"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
@@ -32,7 +32,7 @@ module "zed" {
|
||||
module "zed" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/zed/coder"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder/project"
|
||||
}
|
||||
@@ -44,7 +44,7 @@ module "zed" {
|
||||
module "zed" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/zed/coder"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Zed Editor"
|
||||
order = 1
|
||||
@@ -57,7 +57,7 @@ module "zed" {
|
||||
module "zed" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/zed/coder"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = coder_agent.example.name
|
||||
}
|
||||
@@ -73,7 +73,7 @@ You can declaratively set/merge settings with the `settings` input. Provide a JS
|
||||
module "zed" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/zed/coder"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
settings = jsonencode({
|
||||
@@ -85,6 +85,7 @@ module "zed" {
|
||||
env = {}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import {
|
||||
execContainer,
|
||||
findResourceInstance,
|
||||
removeContainer,
|
||||
runContainer,
|
||||
runTerraformApply,
|
||||
runTerraformInit,
|
||||
testRequiredVariables,
|
||||
@@ -12,66 +16,114 @@ describe("zed", async () => {
|
||||
agent_id: "foo",
|
||||
});
|
||||
|
||||
it("default output", async () => {
|
||||
it("creates settings file with correct JSON", async () => {
|
||||
const settings = {
|
||||
theme: "One Dark",
|
||||
buffer_font_size: 14,
|
||||
vim_mode: true,
|
||||
telemetry: {
|
||||
diagnostics: false,
|
||||
metrics: false,
|
||||
},
|
||||
// Test special characters: single quotes, backslashes, URLs
|
||||
message: "it's working",
|
||||
path: "C:\\Users\\test",
|
||||
api_url: "https://api.example.com/v1?token=abc&user=test",
|
||||
};
|
||||
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
settings: JSON.stringify(settings),
|
||||
});
|
||||
expect(state.outputs.zed_url.value).toBe("zed://ssh/default.coder");
|
||||
|
||||
const coder_app = state.resources.find(
|
||||
(res) => res.type === "coder_app" && res.name === "zed",
|
||||
);
|
||||
const instance = findResourceInstance(state, "coder_script");
|
||||
const id = await runContainer("alpine:latest");
|
||||
|
||||
expect(coder_app).not.toBeNull();
|
||||
expect(coder_app?.instances.length).toBe(1);
|
||||
expect(coder_app?.instances[0].attributes.order).toBeNull();
|
||||
});
|
||||
try {
|
||||
const result = await execContainer(id, ["sh", "-c", instance.script]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
const catResult = await execContainer(id, [
|
||||
"cat",
|
||||
"/root/.config/zed/settings.json",
|
||||
]);
|
||||
expect(catResult.exitCode).toBe(0);
|
||||
|
||||
const written = JSON.parse(catResult.stdout.trim());
|
||||
expect(written).toEqual(settings);
|
||||
} finally {
|
||||
await removeContainer(id);
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
it("merges settings with existing file when jq available", async () => {
|
||||
const existingSettings = {
|
||||
theme: "Solarized Dark",
|
||||
vim_mode: true,
|
||||
};
|
||||
|
||||
const newSettings = {
|
||||
theme: "One Dark",
|
||||
buffer_font_size: 14,
|
||||
};
|
||||
|
||||
it("adds folder", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
folder: "/foo/bar",
|
||||
settings: JSON.stringify(newSettings),
|
||||
});
|
||||
expect(state.outputs.zed_url.value).toBe("zed://ssh/default.coder/foo/bar");
|
||||
});
|
||||
|
||||
it("expect order to be set", async () => {
|
||||
const instance = findResourceInstance(state, "coder_script");
|
||||
const id = await runContainer("alpine:latest");
|
||||
|
||||
try {
|
||||
// Install jq and create existing settings file
|
||||
await execContainer(id, ["apk", "add", "--no-cache", "jq"]);
|
||||
await execContainer(id, ["mkdir", "-p", "/root/.config/zed"]);
|
||||
await execContainer(id, [
|
||||
"sh",
|
||||
"-c",
|
||||
`echo '${JSON.stringify(existingSettings)}' > /root/.config/zed/settings.json`,
|
||||
]);
|
||||
|
||||
const result = await execContainer(id, ["sh", "-c", instance.script]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
const catResult = await execContainer(id, [
|
||||
"cat",
|
||||
"/root/.config/zed/settings.json",
|
||||
]);
|
||||
expect(catResult.exitCode).toBe(0);
|
||||
|
||||
const merged = JSON.parse(catResult.stdout.trim());
|
||||
expect(merged.theme).toBe("One Dark"); // overwritten
|
||||
expect(merged.buffer_font_size).toBe(14); // added
|
||||
expect(merged.vim_mode).toBe(true); // preserved
|
||||
} finally {
|
||||
await removeContainer(id);
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
it("exits early with empty settings", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
order: "22",
|
||||
settings: "",
|
||||
});
|
||||
|
||||
const coder_app = state.resources.find(
|
||||
(res) => res.type === "coder_app" && res.name === "zed",
|
||||
);
|
||||
const instance = findResourceInstance(state, "coder_script");
|
||||
const id = await runContainer("alpine:latest");
|
||||
|
||||
expect(coder_app).not.toBeNull();
|
||||
expect(coder_app?.instances.length).toBe(1);
|
||||
expect(coder_app?.instances[0].attributes.order).toBe(22);
|
||||
});
|
||||
try {
|
||||
const result = await execContainer(id, ["sh", "-c", instance.script]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
it("expect display_name to be set", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
display_name: "Custom Zed",
|
||||
});
|
||||
|
||||
const coder_app = state.resources.find(
|
||||
(res) => res.type === "coder_app" && res.name === "zed",
|
||||
);
|
||||
|
||||
expect(coder_app).not.toBeNull();
|
||||
expect(coder_app?.instances.length).toBe(1);
|
||||
expect(coder_app?.instances[0].attributes.display_name).toBe("Custom Zed");
|
||||
});
|
||||
|
||||
it("adds agent_name to hostname", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
agent_name: "myagent",
|
||||
});
|
||||
expect(state.outputs.zed_url.value).toBe(
|
||||
"zed://ssh/myagent.default.default.coder",
|
||||
);
|
||||
});
|
||||
// Settings file should not be created
|
||||
const catResult = await execContainer(id, [
|
||||
"cat",
|
||||
"/root/.config/zed/settings.json",
|
||||
]);
|
||||
expect(catResult.exitCode).not.toBe(0);
|
||||
} finally {
|
||||
await removeContainer(id);
|
||||
}
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
@@ -65,6 +65,7 @@ locals {
|
||||
owner_name = lower(data.coder_workspace_owner.me.name)
|
||||
agent_name = lower(var.agent_name)
|
||||
hostname = var.agent_name != "" ? "${local.agent_name}.${local.workspace_name}.${local.owner_name}.coder" : "${local.workspace_name}.coder"
|
||||
settings_b64 = var.settings != "" ? base64encode(var.settings) : ""
|
||||
}
|
||||
|
||||
resource "coder_script" "zed_settings" {
|
||||
@@ -75,7 +76,11 @@ resource "coder_script" "zed_settings" {
|
||||
script = <<-EOT
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
SETTINGS_JSON='${replace(var.settings, "\"", "\\\"")}'
|
||||
SETTINGS_B64='${local.settings_b64}'
|
||||
if [ -z "$${SETTINGS_B64}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
SETTINGS_JSON="$(echo -n "$${SETTINGS_B64}" | base64 -d)"
|
||||
if [ -z "$${SETTINGS_JSON}" ] || [ "$${SETTINGS_JSON}" = "{}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -5,6 +5,20 @@ run "default_output" {
|
||||
agent_id = "foo"
|
||||
}
|
||||
|
||||
override_data {
|
||||
target = data.coder_workspace.me
|
||||
values = {
|
||||
name = "default"
|
||||
}
|
||||
}
|
||||
|
||||
override_data {
|
||||
target = data.coder_workspace_owner.me
|
||||
values = {
|
||||
name = "default"
|
||||
}
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.zed_url == "zed://ssh/default.coder"
|
||||
error_message = "zed_url did not match expected default URL"
|
||||
@@ -19,6 +33,20 @@ run "adds_folder" {
|
||||
folder = "/foo/bar"
|
||||
}
|
||||
|
||||
override_data {
|
||||
target = data.coder_workspace.me
|
||||
values = {
|
||||
name = "default"
|
||||
}
|
||||
}
|
||||
|
||||
override_data {
|
||||
target = data.coder_workspace_owner.me
|
||||
values = {
|
||||
name = "default"
|
||||
}
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.zed_url == "zed://ssh/default.coder/foo/bar"
|
||||
error_message = "zed_url did not include provided folder path"
|
||||
@@ -33,8 +61,54 @@ run "adds_agent_name" {
|
||||
agent_name = "myagent"
|
||||
}
|
||||
|
||||
override_data {
|
||||
target = data.coder_workspace.me
|
||||
values = {
|
||||
name = "default"
|
||||
}
|
||||
}
|
||||
|
||||
override_data {
|
||||
target = data.coder_workspace_owner.me
|
||||
values = {
|
||||
name = "default"
|
||||
}
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.zed_url == "zed://ssh/myagent.default.default.coder"
|
||||
error_message = "zed_url did not include agent_name in hostname"
|
||||
}
|
||||
}
|
||||
|
||||
run "settings_base64_encoding" {
|
||||
command = apply
|
||||
|
||||
variables {
|
||||
agent_id = "foo"
|
||||
settings = jsonencode({
|
||||
theme = "dark"
|
||||
fontSize = 14
|
||||
})
|
||||
}
|
||||
|
||||
# Verify settings are base64 encoded (eyJ = base64 prefix for JSON starting with {")
|
||||
assert {
|
||||
condition = can(regex("SETTINGS_B64='eyJ", coder_script.zed_settings.script))
|
||||
error_message = "settings should be base64 encoded in the script"
|
||||
}
|
||||
}
|
||||
|
||||
run "empty_settings" {
|
||||
command = apply
|
||||
|
||||
variables {
|
||||
agent_id = "foo"
|
||||
settings = ""
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = can(regex("SETTINGS_B64=''", coder_script.zed_settings.script))
|
||||
error_message = "empty settings should result in empty SETTINGS_B64"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ variable "cache_repo_secret_name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
data "kubernetes_secret" "cache_repo_dockerconfig_secret" {
|
||||
data "kubernetes_secret_v1" "cache_repo_dockerconfig_secret" {
|
||||
count = var.cache_repo_secret_name == "" ? 0 : 1
|
||||
metadata {
|
||||
name = var.cache_repo_secret_name
|
||||
@@ -166,7 +166,7 @@ locals {
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
"ENVBUILDER_INIT_SCRIPT" : replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
|
||||
"ENVBUILDER_FALLBACK_IMAGE" : data.coder_parameter.fallback_image.value,
|
||||
"ENVBUILDER_DOCKER_CONFIG_BASE64" : base64encode(try(data.kubernetes_secret.cache_repo_dockerconfig_secret[0].data[".dockerconfigjson"], "")),
|
||||
"ENVBUILDER_DOCKER_CONFIG_BASE64" : base64encode(try(data.kubernetes_secret_v1.cache_repo_dockerconfig_secret[0].data[".dockerconfigjson"], "")),
|
||||
"ENVBUILDER_PUSH_IMAGE" : var.cache_repo == "" ? "" : "true"
|
||||
# You may need to adjust this if you get an error regarding deleting files when building the workspace.
|
||||
# For example, when testing in KinD, it was necessary to set `/product_name` and `/product_uuid` in
|
||||
@@ -186,7 +186,7 @@ resource "envbuilder_cached_image" "cached" {
|
||||
insecure = var.insecure_cache_repo
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume_claim" "workspaces" {
|
||||
resource "kubernetes_persistent_volume_claim_v1" "workspaces" {
|
||||
metadata {
|
||||
name = "coder-${lower(data.coder_workspace.me.id)}-workspaces"
|
||||
namespace = var.namespace
|
||||
@@ -217,10 +217,10 @@ resource "kubernetes_persistent_volume_claim" "workspaces" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "main" {
|
||||
resource "kubernetes_deployment_v1" "main" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
depends_on = [
|
||||
kubernetes_persistent_volume_claim.workspaces
|
||||
kubernetes_persistent_volume_claim_v1.workspaces
|
||||
]
|
||||
wait_for_rollout = false
|
||||
metadata {
|
||||
@@ -300,7 +300,7 @@ resource "kubernetes_deployment" "main" {
|
||||
volume {
|
||||
name = "workspaces"
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.workspaces.metadata.0.name
|
||||
claim_name = kubernetes_persistent_volume_claim_v1.workspaces.metadata.0.name
|
||||
read_only = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,22 +106,20 @@ module "code-server" {
|
||||
# This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
|
||||
version = "~> 1.0"
|
||||
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
order = 1
|
||||
agent_id = coder_agent.main.id
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/modules/coder/jetbrains/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
folder = "/home/coder"
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume_claim" "home" {
|
||||
resource "kubernetes_persistent_volume_claim_v1" "home" {
|
||||
metadata {
|
||||
name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}-home"
|
||||
namespace = var.namespace
|
||||
@@ -137,7 +135,7 @@ resource "kubernetes_persistent_volume_claim" "home" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_pod" "main" {
|
||||
resource "kubernetes_pod_v1" "main" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
|
||||
metadata {
|
||||
@@ -284,7 +282,7 @@ resource "kubernetes_pod" "main" {
|
||||
volume {
|
||||
name = "home"
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.home.metadata.0.name
|
||||
claim_name = kubernetes_persistent_volume_claim_v1.home.metadata.0.name
|
||||
read_only = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ resource "coder_app" "code-server" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume_claim" "home" {
|
||||
resource "kubernetes_persistent_volume_claim_v1" "home" {
|
||||
metadata {
|
||||
name = "coder-${data.coder_workspace.me.id}-home"
|
||||
namespace = var.namespace
|
||||
@@ -222,10 +222,10 @@ resource "kubernetes_persistent_volume_claim" "home" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "main" {
|
||||
resource "kubernetes_deployment_v1" "main" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
depends_on = [
|
||||
kubernetes_persistent_volume_claim.home
|
||||
kubernetes_persistent_volume_claim_v1.home
|
||||
]
|
||||
wait_for_rollout = false
|
||||
metadata {
|
||||
@@ -316,7 +316,7 @@ resource "kubernetes_deployment" "main" {
|
||||
volume {
|
||||
name = "home"
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.home.metadata.0.name
|
||||
claim_name = kubernetes_persistent_volume_claim_v1.home.metadata.0.name
|
||||
read_only = false
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 460 B |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 461 KiB After Width: | Height: | Size: 330 KiB |
|
Before Width: | Height: | Size: 632 KiB After Width: | Height: | Size: 631 KiB |