Adding a New Language
Adding a new language to DevRail involves changes across multiple repositories. This guide walks through the complete process.
Canonical Reference
The authoritative, detailed version of this guide with full code templates and concrete examples lives in thedevrail-standards repo at standards/contributing-a-language.md. This page provides the overview; the canonical guide provides copy-pasteable templates for every step.Overview
Adding a language ecosystem requires updates to six areas:
- Install script in
dev-toolchain– installs the language’s tools in the container - Makefile targets in
dev-toolchain– adds_lint,_format,_test,_securitytargets - Pre-commit hooks – configures local hooks for the new language
- Standards document in
devrail-standards– documents the tools and conventions - Verification tests in
dev-toolchain– validates all tools work correctly - Schema update in
devrail-standards– adds the new language to.devrail.ymlaccepted values
Step 1: Create the Install Script
Create scripts/install-<language>.sh in the dev-toolchain repository. The script must follow DevRail shell conventions:
#!/usr/bin/env bash
# Purpose: Install <language> development tools
# Usage: install-<language>.sh
# Dependencies: curl, apt-get (or appropriate package manager)
set -euo pipefail
# Source shared logging library
source "$(dirname "$0")/../lib/log.sh"
install_linter() {
# Check before installing (idempotent)
if command -v <linter> > /dev/null 2>&1; then
log_info "<linter> already installed"
return 0
fi
log_info "Installing <linter>..."
# Installation commands here
}
install_formatter() {
if command -v <formatter> > /dev/null 2>&1; then
log_info "<formatter> already installed"
return 0
fi
log_info "Installing <formatter>..."
# Installation commands here
}
# Main
install_linter
install_formatter
log_info "<language> tools installed successfully"
Key requirements:
- Idempotent – check before installing, safe to re-run
- Uses
lib/log.sh– no rawechofor status messages - Self-documenting header – purpose, usage, dependencies
Step 2: Add Makefile Targets
Add internal targets to the dev-toolchain Makefile for the new language:
# Internal targets for <language>
_lint-<language>:
<linter-command>
_format-<language>:
<formatter-command>
_test-<language>:
<test-runner-command>
_security-<language>:
<security-scanner-command>
Update the existing _lint, _format, _test, and _security targets to include the new language when it is declared in .devrail.yml.
Step 3: Configure Pre-Commit Hooks
Add pre-commit hook entries for the new language’s local hooks (those that run in under 30 seconds):
# .pre-commit-config.yaml additions for <language>
repos:
- repo: https://github.com/<org>/<linter-hook>
rev: ""
hooks:
- id: <linter>
- repo: https://github.com/<org>/<formatter-hook>
rev: ""
hooks:
- id: <formatter>
Remember the split: fast hooks (linting, formatting) run locally; slow hooks (security scanning, full tests) run in CI only.
Step 4: Write the Standards Document
Create standards/<language>.md in the devrail-standards repository. Follow the consistent structure used by all per-language standards pages:
# <Language> Standards
## Tools
| Concern | Tool | Version Strategy |
|---|---|---|
| Linter | <linter> | Latest in container |
| Formatter | <formatter> | Latest in container |
| Security | <scanner> | Latest in container |
| Tests | <test-runner> | Latest in container |
## Configuration
[Configuration file examples with inline comments]
## Makefile Targets
[Which targets run which tools]
## Pre-Commit Hooks
[Local hooks and CI-only hooks]
## Notes
[Important conventions and gotchas]
Step 5: Write Verification Tests
Create tests/test-<language>.sh in the dev-toolchain repository:
#!/usr/bin/env bats
# tests/test-<language>.sh -- verify <language> tools are installed and working
@test "<linter> is installed" {
run command -v <linter>
[ "$status" -eq 0 ]
}
@test "<linter> runs successfully" {
run <linter> --version
[ "$status" -eq 0 ]
}
@test "<formatter> is installed" {
run command -v <formatter>
[ "$status" -eq 0 ]
}
Step 6: Update the .devrail.yml Schema
In devrail-standards, update standards/devrail-yml-schema.md to add the new language to the list of allowed values for the languages key:
# Updated allowed values
languages:
- python
- bash
- terraform
- ansible
- <new-language> # Add the new language
Checklist
Before submitting your pull requests, verify:
- Install script is idempotent (safe to re-run)
- Install script uses
lib/log.shfor logging - All tools install and run inside the dev-toolchain container
- Makefile targets follow the naming conventions (
_lint,_format,_test,_security) - Pre-commit hooks complete in under 30 seconds
- Standards document follows the consistent structure
- Verification tests pass inside the container
-
.devrail.ymlschema is updated - All commits use conventional commit format
Pull Request Strategy
Adding a new language requires coordinated changes across multiple repos. Submit PRs in this order:
dev-toolchain– install script + Makefile targets + testsdevrail-standards– standards document + schema update- Templates – update
.pre-commit-config.yamlwith new hooks devrail.dev– add documentation page for the new language