Skip to content

Commit 6746e16

Browse files
docs: add contribution documentation for modules and templates (#18820)
draft: add contribution docs for modules and templates individually to be referenced in coder docs manifest. --------- Co-authored-by: Atif Ali <atif@coder.com>
1 parent 183a6eb commit 6746e16

File tree

3 files changed

+932
-0
lines changed

3 files changed

+932
-0
lines changed

docs/about/contributing/modules.md

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
# Contributing modules
2+
3+
Learn how to create and contribute Terraform modules to the Coder Registry. Modules provide reusable components that extend Coder workspaces with IDEs, development tools, login tools, and other features.
4+
5+
## What are Coder modules
6+
7+
Coder modules are Terraform modules that integrate with Coder workspaces to provide specific functionality. They are published to the Coder Registry at [registry.coder.com](https://registry.coder.com) and can be consumed in any Coder template using standard Terraform module syntax.
8+
9+
Examples of modules include:
10+
11+
- **Desktop IDEs**: [`jetbrains-fleet`](https://registry.coder.com/modules/coder/jetbrains-fleet), [`cursor`](https://registry.coder.com/modules/coder/cursor), [`windsurf`](https://registry.coder.com/modules/coder/windsurf), [`zed`](https://registry.coder.com/modules/coder/zed)
12+
- **Web IDEs**: [`code-server`](https://registry.coder.com/modules/coder/code-server), [`vscode-web`](https://registry.coder.com/modules/coder/vscode-web), [`jupyter-notebook`](https://registry.coder.com/modules/coder/jupyter-notebook), [`jupyter-lab`](https://registry.coder.com/modules/coder/jupyterlab)
13+
- **Integrations**: [`devcontainers-cli`](https://registry.coder.com/modules/coder/devcontainers-cli), [`vault-github`](https://registry.coder.com/modules/coder/vault-github), [`jfrog-oauth`](https://registry.coder.com/modules/coder/jfrog-oauth), [`jfrog-token`](https://registry.coder.com/modules/coder/jfrog-token)
14+
- **Workspace utilities**: [`git-clone`](https://registry.coder.com/modules/coder/git-clone), [`dotfiles`](https://registry.coder.com/modules/coder/dotfiles), [`filebrowser`](https://registry.coder.com/modules/coder/filebrowser), [`coder-login`](https://registry.coder.com/modules/coder/coder-login), [`personalize`](https://registry.coder.com/modules/coder/personalize)
15+
16+
## Prerequisites
17+
18+
Before contributing modules, ensure you have:
19+
20+
- Basic Terraform knowledge
21+
- [Terraform installed](https://developer.hashicorp.com/terraform/install)
22+
- [Docker installed](https://docs.docker.com/get-docker/) (for running tests)
23+
- [Bun installed](https://bun.sh/docs/installation) (for running tests and tooling)
24+
25+
## Setup your development environment
26+
27+
1. **Fork and clone the repository**:
28+
29+
```bash
30+
git clone https://github.com/your-username/registry.git
31+
cd registry
32+
```
33+
34+
2. **Install dependencies**:
35+
36+
```bash
37+
bun install
38+
```
39+
40+
3. **Understand the structure**:
41+
42+
```text
43+
registry/[namespace]/
44+
├── modules/ # Your modules
45+
├── .images/ # Namespace avatar and screenshots
46+
└── README.md # Namespace description
47+
```
48+
49+
## Create your first module
50+
51+
### 1. Set up your namespace
52+
53+
If you're a new contributor, create your namespace directory:
54+
55+
```bash
56+
mkdir -p registry/[your-username]
57+
mkdir -p registry/[your-username]/.images
58+
```
59+
60+
Add your namespace avatar by downloading your GitHub avatar and saving it as `avatar.png`:
61+
62+
```bash
63+
curl -o registry/[your-username]/.images/avatar.png https://github.com/[your-username].png
64+
```
65+
66+
Create your namespace README at `registry/[your-username]/README.md`:
67+
68+
```markdown
69+
---
70+
display_name: "Your Name"
71+
bio: "Brief description of what you do"
72+
github: "your-username"
73+
avatar: "./.images/avatar.png"
74+
linkedin: "https://www.linkedin.com/in/your-username"
75+
website: "https://your-website.com"
76+
support_email: "support@your-domain.com"
77+
status: "community"
78+
---
79+
80+
# Your Name
81+
82+
Brief description of who you are and what you do.
83+
```
84+
85+
> [!NOTE]
86+
> The `linkedin`, `website`, and `support_email` fields are optional and can be omitted or left empty if not applicable.
87+
88+
### 2. Generate module scaffolding
89+
90+
Use the provided script to generate your module structure:
91+
92+
```bash
93+
./scripts/new_module.sh [your-username]/[module-name]
94+
cd registry/[your-username]/modules/[module-name]
95+
```
96+
97+
This creates:
98+
99+
- `main.tf` - Terraform configuration template
100+
- `README.md` - Documentation template with frontmatter
101+
- `run.sh` - Optional execution script
102+
103+
### 3. Implement your module
104+
105+
Edit `main.tf` to build your module's features. Here's an example based on the `git-clone` module structure:
106+
107+
```terraform
108+
terraform {
109+
required_providers {
110+
coder = {
111+
source = "coder/coder"
112+
}
113+
}
114+
}
115+
116+
# Input variables
117+
variable "agent_id" {
118+
description = "The ID of a Coder agent"
119+
type = string
120+
}
121+
122+
variable "url" {
123+
description = "Git repository URL to clone"
124+
type = string
125+
validation {
126+
condition = can(regex("^(https?://|git@)", var.url))
127+
error_message = "URL must be a valid git repository URL."
128+
}
129+
}
130+
131+
variable "base_dir" {
132+
description = "Directory to clone the repository into"
133+
type = string
134+
default = "~"
135+
}
136+
137+
# Resources
138+
resource "coder_script" "clone_repo" {
139+
agent_id = var.agent_id
140+
display_name = "Clone Repository"
141+
script = <<-EOT
142+
#!/bin/bash
143+
set -e
144+
145+
# Ensure git is installed
146+
if ! command -v git &> /dev/null; then
147+
echo "Installing git..."
148+
sudo apt-get update && sudo apt-get install -y git
149+
fi
150+
151+
# Clone repository if it doesn't exist
152+
if [ ! -d "${var.base_dir}/$(basename ${var.url} .git)" ]; then
153+
echo "Cloning ${var.url}..."
154+
git clone ${var.url} ${var.base_dir}/$(basename ${var.url} .git)
155+
fi
156+
EOT
157+
run_on_start = true
158+
}
159+
160+
# Outputs
161+
output "repo_dir" {
162+
description = "Path to the cloned repository"
163+
value = "${var.base_dir}/$(basename ${var.url} .git)"
164+
}
165+
```
166+
167+
### 4. Write complete tests
168+
169+
Create `main.test.ts` to test your module features:
170+
171+
```typescript
172+
import { runTerraformApply, runTerraformInit, testRequiredVariables } from "~test"
173+
174+
describe("git-clone", async () => {
175+
await testRequiredVariables("registry/[your-username]/modules/git-clone")
176+
177+
it("should clone repository successfully", async () => {
178+
await runTerraformInit("registry/[your-username]/modules/git-clone")
179+
await runTerraformApply("registry/[your-username]/modules/git-clone", {
180+
agent_id: "test-agent-id",
181+
url: "https://github.com/coder/coder.git",
182+
base_dir: "/tmp"
183+
})
184+
})
185+
186+
it("should work with SSH URLs", async () => {
187+
await runTerraformInit("registry/[your-username]/modules/git-clone")
188+
await runTerraformApply("registry/[your-username]/modules/git-clone", {
189+
agent_id: "test-agent-id",
190+
url: "git@github.com:coder/coder.git"
191+
})
192+
})
193+
})
194+
```
195+
196+
### 5. Document your module
197+
198+
Update `README.md` with complete documentation:
199+
200+
```markdown
201+
---
202+
display_name: "Git Clone"
203+
description: "Clone a Git repository into your Coder workspace"
204+
icon: "../../../../.icons/git.svg"
205+
verified: false
206+
tags: ["git", "development", "vcs"]
207+
---
208+
209+
# Git Clone
210+
211+
This module clones a Git repository into your Coder workspace and ensures Git is installed.
212+
213+
## Usage
214+
215+
```tf
216+
module "git_clone" {
217+
source = "registry.coder.com/[your-username]/git-clone/coder"
218+
version = "~> 1.0"
219+
220+
agent_id = coder_agent.main.id
221+
url = "https://github.com/coder/coder.git"
222+
base_dir = "/home/coder/projects"
223+
}
224+
```
225+
226+
## Module best practices
227+
228+
### Design principles
229+
230+
- **Single responsibility**: Each module should have one clear purpose
231+
- **Reusability**: Design for use across different workspace types
232+
- **Flexibility**: Provide sensible defaults but allow customization
233+
- **Safe to rerun**: Ensure modules can be applied multiple times safely
234+
235+
### Terraform conventions
236+
237+
- Use descriptive variable names and include descriptions
238+
- Provide default values for optional variables
239+
- Include helpful outputs for working with other modules
240+
- Use proper resource dependencies
241+
- Follow [Terraform style conventions](https://developer.hashicorp.com/terraform/language/syntax/style)
242+
243+
### Documentation standards
244+
245+
Your module README should include:
246+
247+
- **Frontmatter**: Required metadata for the registry
248+
- **Description**: Clear explanation of what the module does
249+
- **Usage example**: Working Terraform code snippet
250+
- **Additional context**: Setup requirements, known limitations, etc.
251+
252+
> [!NOTE]
253+
> Do not include variables tables in your README. The registry automatically generates variable documentation from your `main.tf` file.
254+
255+
## Test your module
256+
257+
Run tests to ensure your module works correctly:
258+
259+
```bash
260+
# Test your specific module
261+
bun test -t 'git-clone'
262+
263+
# Test all modules
264+
bun test
265+
266+
# Format code
267+
bun fmt
268+
```
269+
270+
> [!IMPORTANT]
271+
> Tests require Docker with `--network=host` support, which typically requires Linux. macOS users can use [Colima](https://github.com/abiosoft/colima) or [OrbStack](https://orbstack.dev/) instead of Docker Desktop.
272+
273+
## Contribute to existing modules
274+
275+
### Types of contributions
276+
277+
**Bug fixes**:
278+
279+
- Fix installation or configuration issues
280+
- Resolve compatibility problems
281+
- Correct documentation errors
282+
283+
**Feature additions**:
284+
285+
- Add new configuration options
286+
- Support additional platforms or versions
287+
- Add new features
288+
289+
**Maintenance**:
290+
291+
- Update dependencies
292+
- Improve error handling
293+
- Optimize performance
294+
295+
### Making changes
296+
297+
1. **Identify the issue**: Reproduce the problem or identify the improvement needed
298+
2. **Make focused changes**: Keep modifications minimal and targeted
299+
3. **Maintain compatibility**: Ensure existing users aren't broken
300+
4. **Add tests**: Test new features and edge cases
301+
5. **Update documentation**: Reflect changes in the README
302+
303+
### Backward compatibility
304+
305+
When modifying existing modules:
306+
307+
- Add new variables with sensible defaults
308+
- Don't remove existing variables without a migration path
309+
- Don't change variable types or meanings
310+
- Test that basic configurations still work
311+
312+
## Versioning
313+
314+
When you modify a module, update its version following semantic versioning:
315+
316+
- **Patch** (1.0.0 → 1.0.1): Bug fixes, documentation updates
317+
- **Minor** (1.0.0 → 1.1.0): New features, new variables
318+
- **Major** (1.0.0 → 2.0.0): Breaking changes, removing variables
319+
320+
Use the version bump script to update versions:
321+
322+
```bash
323+
./.github/scripts/version-bump.sh patch|minor|major
324+
```
325+
326+
## Submit your contribution
327+
328+
1. **Create a feature branch**:
329+
330+
```bash
331+
git checkout -b feat/modify-git-clone-module
332+
```
333+
334+
2. **Test thoroughly**:
335+
336+
```bash
337+
bun test -t 'git-clone'
338+
bun fmt
339+
```
340+
341+
3. **Commit with clear messages**:
342+
343+
```bash
344+
git add .
345+
git commit -m "feat(git-clone):add git-clone module"
346+
```
347+
348+
4. **Open a pull request**:
349+
- Use a descriptive title
350+
- Explain what the module does and why it's useful
351+
- Reference any related issues
352+
353+
## Common issues and solutions
354+
355+
### Testing problems
356+
357+
**Issue**: Tests fail with network errors
358+
**Solution**: Ensure Docker is running with `--network=host` support
359+
360+
### Module development
361+
362+
**Issue**: Icon not displaying
363+
**Solution**: Verify icon path is correct and file exists in `.icons/` directory
364+
365+
### Documentation
366+
367+
**Issue**: Code blocks not syntax highlighted
368+
**Solution**: Use `tf` language identifier for Terraform code blocks
369+
370+
## Get help
371+
372+
- **Examples**: Review existing modules like [`code-server`](https://registry.coder.com/modules/coder/code-server), [`git-clone`](https://registry.coder.com/modules/coder/git-clone), and [`jetbrains-gateway`](https://registry.coder.com/modules/coder/jetbrains-gateway)
373+
- **Issues**: Open an issue at [github.com/coder/registry](https://github.com/coder/registry/issues)
374+
- **Community**: Join the [Coder Discord](https://discord.gg/coder) for questions
375+
- **Documentation**: Check the [Coder docs](https://coder.com/docs) for help on Coder.
376+
377+
## Next steps
378+
379+
After creating your first module:
380+
381+
1. **Share with the community**: Announce your module on Discord or social media
382+
2. **Iterate based on feedback**: Improve based on user suggestions
383+
3. **Create more modules**: Build a collection of related tools
384+
4. **Contribute to existing modules**: Help maintain and improve the ecosystem
385+
386+
Happy contributing! 🚀

0 commit comments

Comments
 (0)