Merge branch 'main' into module-screenshots

merge main
pull/63/head
Stephen Kirby 2 years ago
commit 3433cc4432

@ -21,11 +21,14 @@ jobs:
with:
bun-version: latest
- run: bun test
fmt:
pretty:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- run: bun fmt:ci
- name: Format
run: bun fmt:ci
- name: Lint
run: bun install && bun lint

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 KiB

@ -11,14 +11,14 @@ tags: [helper]
<!-- Describes what this module does -->
<!-- Add a screencast or screenshot here put them in .images directory -->
```hcl
module "MODULE_NAME" {
source = "https://registry.coder.com/modules/MODULE_NAME"
}
```
<!-- Add a screencast or screenshot here put them in .images directory -->
## Examples
### Example 1

@ -1,7 +1,7 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
echo "$${BOLD}Installing MODULE_NAME..."
printf "$${BOLD}Installing MODULE_NAME..."
# Add code here
# Use varibles from the templatefile function in main.tf
# e.g. LOG_PATH, PORT, etc.

Binary file not shown.

@ -26,6 +26,12 @@ variable "port" {
default = 13337
}
variable "display_name" {
type = string
description = "The display name for the code-server application."
default = "code-server"
}
variable "settings" {
type = map(string)
description = "A map of settings to apply to code-server."
@ -75,7 +81,7 @@ resource "coder_script" "code-server" {
resource "coder_app" "code-server" {
agent_id = var.agent_id
slug = "code-server"
display_name = "code-server"
display_name = var.display_name
url = "http://localhost:${var.port}/${var.folder != "" ? "?folder=${urlencode(var.folder)}" : ""}"
icon = "/icon/code.svg"
subdomain = false

@ -41,7 +41,7 @@ done
if [ ! -f ~/.local/share/code-server/Machine/settings.json ]; then
echo "⚙️ Creating settings file..."
mkdir -p ~/.local/share/code-server/Machine
echo "${SETTINGS}" > ~/.local/share/code-server/Machine/settings.json
echo "${SETTINGS}" >~/.local/share/code-server/Machine/settings.json
fi
echo "👷 Running code-server in the background..."

@ -1,7 +1,7 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
echo "$${BOLD}Installing filebrowser \n\n"
printf "$${BOLD}Installing filebrowser \n\n"
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash

@ -27,11 +27,12 @@ variable "agent_id" {
resource "coder_script" "git_clone" {
agent_id = var.agent_id
display_name = "Git Clone"
icon = "/icons/git.svg"
script = templatefile("${path.module}/run.sh", {
CLONE_PATH : var.path != "" ? var.path : join("/", ["~", basename(var.url)]),
REPO_URL : var.url,
})
display_name = "Git Clone"
icon = "/icons/git.svg"
run_on_start = true
start_blocks_login = true
}

@ -0,0 +1,48 @@
---
display_name: Git Config
description: Stores Git configuration from Coder credentials
icon: ../.icons/git.svg
maintainer_github: coder
verified: true
tags: [helper, git]
---
# git-config
Runs a script that updates git credentials in the workspace to match the user's Coder credentials, optionally allowing to the developer to override the defaults.
```hcl
module "git-config" {
source = "https://registry.coder.com/modules/git-config"
agent_id = coder_agent.example.id
}
```
TODO: Add screenshot
## Examples
### Allow users to override both username and email
```hcl
module "git-config" {
source = "https://registry.coder.com/modules/git-config"
agent_id = coder_agent.example.id
allow_email_change = true
}
```
TODO: Add screenshot
## Disallowing users from overriding both username and email
```hcl
module "git-config" {
source = "https://registry.coder.com/modules/git-config"
agent_id = coder_agent.example.id
allow_username_change = false
allow_email_change = false
}
```
TODO: Add screenshot

@ -0,0 +1,43 @@
import { describe, expect, it } from "bun:test";
import {
executeScriptInContainer,
runTerraformApply,
runTerraformInit,
testRequiredVariables,
} from "../test";
describe("git-config", async () => {
await runTerraformInit(import.meta.dir);
testRequiredVariables(import.meta.dir, {
agent_id: "foo",
});
it("fails without git", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
});
const output = await executeScriptInContainer(state, "alpine");
expect(output.exitCode).toBe(1);
expect(output.stdout).toEqual([
"\u001B[0;1mChecking git-config!",
"Git is not installed!",
]);
});
it("runs with git", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
});
const output = await executeScriptInContainer(state, "alpine/git");
expect(output.exitCode).toBe(0);
expect(output.stdout).toEqual([
"\u001B[0;1mChecking git-config!",
"git-config: No user.email found, setting to ",
"git-config: No user.name found, setting to default",
"",
"\u001B[0;1mgit-config: using email: ",
"\u001B[0;1mgit-config: using username: default",
]);
});
});

@ -0,0 +1,61 @@
terraform {
required_version = ">= 1.0"
required_providers {
coder = {
source = "coder/coder"
version = ">= 0.12"
}
}
}
variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}
variable "allow_username_change" {
type = bool
description = "Allow developers to change their git username."
default = true
}
variable "allow_email_change" {
type = bool
description = "Allow developers to change their git email."
default = false
}
data "coder_workspace" "me" {}
data "coder_parameter" "user_email" {
count = var.allow_email_change ? 1 : 0
name = "user_email"
type = "string"
default = ""
description = "Git user.email to be used for commits. Leave empty to default to Coder username."
display_name = "Git config user.email"
mutable = true
}
data "coder_parameter" "username" {
count = var.allow_username_change ? 1 : 0
name = "username"
type = "string"
default = ""
description = "Git user.name to be used for commits. Leave empty to default to Coder username."
display_name = "Git config user.name"
mutable = true
}
resource "coder_script" "git_config" {
agent_id = var.agent_id
script = templatefile("${path.module}/run.sh", {
GIT_USERNAME = try(data.coder_parameter.username[0].value, "") == "" ? data.coder_workspace.me.owner : try(data.coder_parameter.username[0].value, "")
GIT_EMAIL = try(data.coder_parameter.user_email[0].value, "") == "" ? data.coder_workspace.me.owner_email : try(data.coder_parameter.user_email[0].value, "")
})
display_name = "Git Config"
icon = "/icon/git.svg"
run_on_start = true
}

@ -0,0 +1,24 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
printf "$${BOLD}Checking git-config!\n"
# Check if git is installed
command -v git >/dev/null 2>&1 || {
echo "Git is not installed!"
exit 1
}
# Set git username and email if missing
if [ -z $(git config --get user.email) ]; then
printf "git-config: No user.email found, setting to ${GIT_EMAIL}\n"
git config --global user.email "${GIT_EMAIL}"
fi
if [ -z $(git config --get user.name) ]; then
printf "git-config: No user.name found, setting to ${GIT_USERNAME}\n"
git config --global user.name "${GIT_USERNAME}"
fi
printf "\n$${BOLD}git-config: using email: $(git config --get user.email)\n"
printf "$${BOLD}git-config: using username: $(git config --get user.name)\n\n"

@ -1,7 +1,7 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
echo "$${BOLD}Installing JFrog CLI..."
printf "$${BOLD}Installing JFrog CLI..."
# Install the JFrog CLI.
curl -fL https://install-cli.jfrog.io | sudo sh
@ -20,11 +20,11 @@ if [ -z "${REPOSITORY_NPM}" ]; then
else
echo "📦 Configuring npm..."
jf npmc --global --repo-resolve "${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM}"
cat << EOF > ~/.npmrc
cat <<EOF >~/.npmrc
email = ${ARTIFACTORY_USERNAME}
registry = ${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM}
EOF
jf rt curl /api/npm/auth >> ~/.npmrc
jf rt curl /api/npm/auth >>~/.npmrc
fi
# Configure the `pip` to use the Artifactory "python" repository.
@ -33,7 +33,7 @@ if [ -z "${REPOSITORY_PYPI}" ]; then
else
echo "🐍 Configuring pip..."
mkdir -p ~/.pip
cat << EOF > ~/.pip/pip.conf
cat <<EOF >~/.pip/pip.conf
[global]
index-url = https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/pypi/${REPOSITORY_PYPI}/simple
EOF

@ -0,0 +1,21 @@
---
display_name: Jupyter Notebook
description: A module that adds Jupyter Notebook in your Coder template.
icon: ../.icons/jupyter.svg
maintainer_github: coder
verified: true
tags: [jupyter, helper, ide, web]
---
# Jupyter Notebook
A module that adds Jupyter Notebook in your Coder template.
![Jupyter Notebook](../.images/jupyter-notebook.png)
```hcl
module "jupyter-notebook" {
source = "https://registry.coder.com/modules/jupyter-notebook"
agent_id = coder_agent.example.id
}
```

@ -0,0 +1,49 @@
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 jupyter notebook to."
default = "/tmp/jupyter-notebook.log"
}
variable "port" {
type = number
description = "The port to run jupyter-notebook on."
default = 19999
}
resource "coder_script" "jupyter-notebook" {
agent_id = var.agent_id
display_name = "jupyter-notebook"
icon = "/icon/jupyter.svg"
script = templatefile("${path.module}/run.sh", {
LOG_PATH : var.log_path,
PORT : var.port
})
run_on_start = true
}
resource "coder_app" "jupyter-notebook" {
agent_id = var.agent_id
slug = "jupyter-notebook"
display_name = "Jupyter Notebook"
url = "http://localhost:${var.port}"
icon = "/icon/jupyter.svg"
subdomain = true
share = "owner"
}

@ -0,0 +1,25 @@
#!/usr/bin/env sh
BOLD='\033[0;1m'
printf "$${BOLD}Installing jupyter-notebook!\n"
# check if jupyter-notebook is installed
if ! command -v jupyter-notebook >/dev/null 2>&1; then
# install jupyter-notebook
# check if python3 pip is installed
if ! command -v pip3 >/dev/null 2>&1; then
echo "pip3 is not installed"
echo "Please install pip3 in your Dockerfile/VM image before running this script"
exit 1
fi
# install jupyter-notebook
pip3 install --upgrade --no-cache-dir --no-warn-script-location jupyter
echo "🥳 jupyter-notebook has been installed\n\n"
else
echo "🥳 jupyter-notebook is already installed\n\n"
fi
echo "👷 Starting jupyter-notebook in background..."
echo "check logs at ${LOG_PATH}"
$HOME/.local/bin/jupyter notebook --NotebookApp.ip='0.0.0.0' --ServerApp.port=${PORT} --no-browser --ServerApp.token='' --ServerApp.password='' >${LOG_PATH} 2>&1 &

@ -2,13 +2,13 @@
BOLD='\033[0;1m'
echo "$${BOLD}Installing jupyterlab!\n"
printf "$${BOLD}Installing jupyterlab!\n"
# check if jupyterlab is installed
if ! command -v jupyterlab > /dev/null 2>&1; then
if ! command -v jupyterlab >/dev/null 2>&1; then
# install jupyterlab
# check if python3 pip is installed
if ! command -v pip3 > /dev/null 2>&1; then
if ! command -v pip3 >/dev/null 2>&1; then
echo "pip3 is not installed"
echo "Please install pip3 in your Dockerfile/VM image before running this script"
exit 1

@ -0,0 +1,96 @@
import { readFile, readdir, stat } from "fs/promises";
import * as path from "path";
import * as marked from "marked";
import grayMatter from "gray-matter";
const files = await readdir(".", { withFileTypes: true });
const dirs = files.filter(
(f) => f.isDirectory() && !f.name.startsWith(".") && f.name !== "node_modules"
);
let badExit = false;
// error reports an error to the console and sets badExit to true
// so that the process will exit with a non-zero exit code.
const error = (...data: any[]) => {
console.error(...data);
badExit = true;
}
// Ensures that each README has the proper format.
// Exits with 0 if all is good!
for (const dir of dirs) {
const readme = path.join(dir.name, "README.md");
// Ensure exists
try {
await stat(readme);
} catch (ex) {
throw new Error(`Missing README.md in ${dir.name}`);
}
const content = await readFile(readme, "utf8");
const matter = grayMatter(content);
const data = matter.data as {
display_name?: string;
description?: string;
icon?: string;
maintainer_github?: string;
partner_github?: string;
verified?: boolean;
tags?: string[];
};
if (!data.display_name) {
error(dir.name, "missing display_name");
}
if (!data.description) {
error(dir.name, "missing description");
}
if (!data.icon) {
error(dir.name, "missing icon");
}
if (!data.maintainer_github) {
error(dir.name, "missing maintainer_github");
}
try {
await stat(path.join(".", dir.name, data.icon));
} catch (ex) {
error(dir.name, "icon does not exist", data.icon);
}
const tokens = marked.lexer(content);
// Ensure there is an h1 and some text, then a code block
let h1 = false;
let code = false;
let paragraph = false;
for (const token of tokens) {
if (token.type === "heading" && token.depth === 1) {
h1 = true;
continue;
}
if (h1 && token.type === "heading") {
break;
}
if (token.type === "paragraph") {
paragraph = true;
continue;
}
if (token.type === "code") {
code = true;
continue;
}
}
if (!h1) {
error(dir.name, "missing h1");
}
if (!paragraph) {
error(dir.name, "missing paragraph after h1");
}
if (!code) {
error(dir.name, "missing example code block after paragraph");
}
}
if (badExit) {
process.exit(1);
}

@ -3,10 +3,13 @@
"scripts": {
"test": "bun test",
"fmt": "bun x prettier -w **/*.ts **/*.md *.md && terraform fmt **/*.tf",
"fmt:ci": "bun x prettier --check **/*.ts **/*.md *.md && terraform fmt -check **/*.tf"
"fmt:ci": "bun x prettier --check **/*.ts **/*.md *.md && terraform fmt -check **/*.tf",
"lint": "bun run lint.ts"
},
"devDependencies": {
"bun-types": "^1.0.3"
"bun-types": "^1.0.3",
"gray-matter": "^4.0.3",
"marked": "^9.0.3"
},
"peerDependencies": {
"typescript": "^5.0.0"

@ -35,4 +35,5 @@ resource "coder_script" "personalize" {
icon = "/icon/personalize.svg"
log_path = var.log_path
run_on_start = true
start_blocks_login = true
}

@ -2,6 +2,8 @@
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"allowSyntheticDefaultImports": true,
"moduleResolution": "nodenext",
"types": ["bun-types"]
}
}

Loading…
Cancel
Save