Skip to content

Commit 6a2e388

Browse files
committed
Initial release v0.1.0
Local development environment framework for web applications. - Config-driven multi-service containers via .scdev/config.yaml - Project isolation via Docker networks with inter-service DNS - Shared services: Traefik router, Mailpit, Adminer, Redis Insights - Automatic HTTPS via mkcert - Mutagen file sync for fast macOS development - Custom project commands via justfiles - Docs page with dynamic project list - Self-update command and install script - GitHub Actions release pipeline
0 parents  commit 6a2e388

94 files changed

Lines changed: 17806 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- uses: actions/setup-go@v5
18+
with:
19+
go-version-file: go.mod
20+
21+
- name: Run tests
22+
run: go test ./...
23+
24+
- name: Build binaries
25+
run: |
26+
VERSION=${GITHUB_REF_NAME}
27+
BUILD_TIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
28+
LDFLAGS="-s -w -X github.com/ScaleCommerce-DEV/scdev/cmd.Version=${VERSION} -X github.com/ScaleCommerce-DEV/scdev/cmd.BuildTime=${BUILD_TIME}"
29+
30+
GOOS=darwin GOARCH=arm64 go build -ldflags "${LDFLAGS}" -o scdev-darwin-arm64 .
31+
GOOS=darwin GOARCH=amd64 go build -ldflags "${LDFLAGS}" -o scdev-darwin-amd64 .
32+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "${LDFLAGS}" -o scdev-linux-amd64 .
33+
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "${LDFLAGS}" -o scdev-linux-arm64 .
34+
35+
# TODO: Add macOS code signing + notarization via quill when Apple certs are configured
36+
37+
- name: Build release body
38+
run: |
39+
cat > release-body.md << 'HEADER'
40+
## Install
41+
42+
**macOS / Linux:**
43+
```bash
44+
curl -fsSL https://raw.githubusercontent.com/ScaleCommerce-DEV/scdev/main/install.sh | sh
45+
```
46+
47+
HEADER
48+
49+
# Extract the latest version section from CHANGELOG.md
50+
if [ -f CHANGELOG.md ]; then
51+
echo "---" >> release-body.md
52+
echo "" >> release-body.md
53+
awk '/^## /{if(found) exit; found=1; next} found{print}' CHANGELOG.md >> release-body.md
54+
fi
55+
56+
- name: Create release
57+
uses: softprops/action-gh-release@v2
58+
with:
59+
body_path: release-body.md
60+
files: |
61+
scdev-darwin-arm64
62+
scdev-darwin-amd64
63+
scdev-linux-amd64
64+
scdev-linux-arm64

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Binary
2+
scdev
3+
scdev-*
4+
5+
# IDE
6+
.idea/
7+
.vscode/
8+
*.swp
9+
*.swo
10+
11+
# OS
12+
.DS_Store
13+
14+
# Test artifacts
15+
coverage.out
16+
17+
# Test server binaries (built via `make test-server`)
18+
testdata/bin/testserver-*

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## v0.1.0
2+
3+
### Initial Release
4+
5+
First public release of scdev - local development environment framework.
6+
7+
- Single-command project startup with `scdev start`
8+
- Config-driven multi-service containers via `.scdev/config.yaml`
9+
- Variable substitution (`${PROJECTNAME}`, `${PROJECTDIR}`, `${SCDEV_DOMAIN}`)
10+
- Project isolation via Docker networks with inter-service DNS
11+
- Named volumes with persistence across restarts
12+
- Project state tracking with `scdev list` and `scdev info`
13+
- Shared Traefik router with automatic HTTPS via mkcert
14+
- Shared Mailpit email catcher
15+
- Shared Adminer database UI
16+
- Shared Redis Insights browser
17+
- Custom project commands via justfiles (`.scdev/commands/`)
18+
- Mutagen file sync for fast macOS development
19+
- Docs page with dynamic project list at `docs.shared.<domain>`
20+
- Self-update command (`scdev update`)
21+
- Install script for macOS and Linux

CLAUDE.md

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
# scdev
2+
3+
Local development environment framework for web applications. Single command startup, shared infrastructure (Traefik, Mailpit, Adminer), project isolation via Docker networks.
4+
5+
## Current Status
6+
7+
**Milestone 12: Shared Redis UI** - Complete. All core milestones done.
8+
9+
## Quick Reference
10+
11+
```bash
12+
make build # Build binary
13+
make build-all # Cross-compile for all platforms
14+
make test # Run unit tests
15+
make test-integration # Run integration tests (requires Docker)
16+
./scdev version # Test the binary
17+
```
18+
19+
## Releases
20+
21+
Releases are automated via GitHub Actions (`.github/workflows/release.yml`).
22+
23+
**Release process:**
24+
1. Update `CHANGELOG.md` — add new `## vX.Y.Z` section at top
25+
2. Commit, tag, push:
26+
```bash
27+
git add CHANGELOG.md
28+
git commit -m "Release vX.Y.Z"
29+
git tag vX.Y.Z
30+
git push origin main && git push origin vX.Y.Z
31+
```
32+
3. CI builds binaries for darwin/linux (arm64/amd64), creates GitHub Release with changelog
33+
34+
**Version injection:** ldflags set `cmd.Version` and `cmd.BuildTime` at build time.
35+
36+
**Self-update:** `scdev self-update` checks GitHub Releases and replaces the binary.
37+
38+
**Install:** `curl -fsSL https://raw.githubusercontent.com/ScaleCommerce-DEV/scdev/main/install.sh | sh`
39+
40+
## Global Flags
41+
42+
| Flag | Description |
43+
|------|-------------|
44+
| `--config <path>` | Path to project directory containing `.scdev/` (overrides auto-discovery) |
45+
46+
**Use case:** Bootstrap projects with tools that require empty directories (e.g., `composer create-project`):
47+
48+
```bash
49+
# 1. Create config in separate location
50+
mkdir -p /tmp/shopware-bootstrap/.scdev
51+
cat > /tmp/shopware-bootstrap/.scdev/config.yaml << 'EOF'
52+
name: shopware
53+
services:
54+
app:
55+
image: php:8.2-cli
56+
volumes:
57+
- /path/to/empty/shopware:/app # Use absolute path
58+
working_dir: /app
59+
EOF
60+
61+
# 2. Start containers with external config
62+
scdev --config /tmp/shopware-bootstrap start
63+
64+
# 3. Run composer in the container
65+
scdev --config /tmp/shopware-bootstrap exec app composer create-project shopware/production .
66+
67+
# 4. Move config into project (optional)
68+
mv /tmp/shopware-bootstrap/.scdev /path/to/empty/shopware/
69+
```
70+
71+
## Project Structure
72+
73+
```
74+
cmd/ # Cobra CLI commands
75+
internal/
76+
config/ # Config parsing, variable substitution
77+
defaults.go # All default values (domain, images, tool versions)
78+
templates/ # Embedded templates with ${VAR} substitution
79+
mutagen/ # Mutagen file sync wrapper
80+
runtime/ # Container runtime abstraction (Docker CLI)
81+
project/ # Project lifecycle, state management
82+
services/ # Shared services (Traefik, Mailpit, Adminer)
83+
tools/ # External tool management (just, mkcert, mutagen)
84+
ui/ # Terminal output helpers
85+
testdata/projects/ # Test fixtures
86+
planning/ # Design docs and implementation plan
87+
```
88+
89+
## Key Decisions
90+
91+
- **Runtime:** Shell out to `docker` CLI (not SDK) - enables future Podman support
92+
- **Global Config:** `~/.scdev/global-config.yaml` - auto-created from template (distinct from project config.yaml)
93+
- **State:** `~/.scdev/state.yaml` - tracks registered projects
94+
- **Defaults:** All in `internal/config/defaults.go` - single source of truth for domain, images, versions
95+
- **Templates:** Embedded via `//go:embed` with `${VAR}` substitution - easy to maintain
96+
- **CLI:** Cobra + Viper
97+
- **Tests:** Unit tests from start, integration tests tagged `//go:build integration`
98+
- **Default Domain:** `scalecommerce.site` - wildcard DNS resolving to 127.0.0.1
99+
100+
## Milestones
101+
102+
| # | Name | Status |
103+
|---|------|--------|
104+
| 0 | Project Skeleton | Done |
105+
| 1 | Single Container | Done |
106+
| 2 | Config-Driven | Done |
107+
| 3 | Networking | Done |
108+
| 4 | Volumes | Done |
109+
| 5 | Project State | Done |
110+
| 6 | Shared Router | Done |
111+
| 7 | SSL & First-Run | Done |
112+
| 8 | Shared Mail | Done |
113+
| 9 | Justfile | Done |
114+
| 10 | Shared DB UI | Done |
115+
| 11 | Mutagen File Sync | Done |
116+
| 12 | Shared Redis UI | Done |
117+
118+
## Shared Services
119+
120+
Shared services run in the `scdev_shared` network and are managed by `internal/services/manager.go`.
121+
122+
| Service | Container | URL | Purpose |
123+
|---------|-----------|-----|---------|
124+
| Docs | (via Traefik Statiq plugin) | `docs.shared.<domain>` | Documentation page, 404 catch-all |
125+
| Router | `scdev_router` | `router.shared.<domain>` | Traefik reverse proxy |
126+
| Mail | `scdev_mail` | `mail.shared.<domain>` | Mailpit email catcher |
127+
| DB UI | `scdev_db` | `db.shared.<domain>` | Adminer database manager |
128+
| Redis UI | `scdev_redis` | `redis.shared.<domain>` | Redis Insights browser |
129+
130+
### Adding New Shared Services
131+
132+
When adding a new shared service:
133+
134+
1. Add container name constant in `internal/services/<service>.go`
135+
2. Add `Start<Service>`, `Stop<Service>`, `<Service>Status` methods to `manager.go`
136+
3. **Update `cmd/services.go` `runServicesRecreate()`** - add stop/remove/start calls
137+
4. Update `cmd/services.go` start/stop/status commands
138+
5. Add image constant to `internal/config/defaults.go`
139+
6. Update `internal/config/config.go` with config struct if needed
140+
141+
The `scdev services recreate` command force-rebuilds all containers - essential when container config changes (new volumes, args, labels).
142+
143+
## Docs Page
144+
145+
The docs page (`docs.shared.<domain>`) is served via Traefik's Statiq plugin and includes:
146+
- Links to all shared services
147+
- **Dynamic projects list** with running/stopped status (updated on every `scdev start/stop/down`)
148+
- Quick start guide and command reference
149+
150+
Unmatched URLs redirect to docs (catch-all route) instead of showing ugly 404.
151+
152+
## Project Config Options
153+
154+
Key project config options in `.scdev/config.yaml`:
155+
156+
| Option | Type | Description |
157+
|--------|------|-------------|
158+
| `auto_open_at_start` | bool | Open project URL in browser after `scdev start` |
159+
| `shared.router` | bool | Connect to shared Traefik router |
160+
| `shared.mail` | bool | Connect to shared Mailpit |
161+
| `shared.db` | bool | Connect to shared Adminer |
162+
| `shared.redis_insights` | bool | Connect to shared Redis Insights |
163+
164+
### Service Config Options
165+
166+
| Option | Type | Description |
167+
|--------|------|-------------|
168+
| `register_to_dbui` | bool | Explicitly register service in Adminer (auto-detected for services named `db`, `mysql`, `postgres`, or images containing those) |
169+
170+
## Justfile Integration
171+
172+
Projects can define custom commands via justfiles in `.scdev/commands/`:
173+
174+
```
175+
.scdev/
176+
commands/
177+
setup.just # scdev setup
178+
test.just # scdev test
179+
build.just # scdev build
180+
```
181+
182+
**Usage:**
183+
```bash
184+
scdev setup # Run default recipe in setup.just
185+
scdev setup install # Run 'install' recipe
186+
scdev setup --list # List available recipes
187+
```
188+
189+
**Environment variables passed to just:**
190+
- `PROJECTNAME` - Project name from config
191+
- `PROJECTPATH` - Absolute path to project
192+
- `PROJECTDIR` - Directory basename
193+
- `SCDEV_DOMAIN` - Base domain (e.g., scalecommerce.site)
194+
- `SCDEV_HOME` - ~/.scdev path
195+
- All project `environment:` vars from config
196+
197+
**Container commands in justfiles:**
198+
Use `scdev exec` to run commands inside containers:
199+
```just
200+
install:
201+
scdev exec app npm ci
202+
203+
test:
204+
scdev exec app npm test
205+
```
206+
207+
**Command resolution:**
208+
1. Check if built-in command (start, stop, exec, etc.)
209+
2. Check if `.scdev/commands/<name>.just` exists
210+
3. Fall back to Cobra's "unknown command" error
211+
212+
## Mutagen File Sync
213+
214+
Mutagen provides fast bidirectional file sync between host filesystem and Docker volumes, solving VirtioFS performance issues on macOS.
215+
216+
**Auto-detection:**
217+
- macOS: Mutagen enabled by default (bind mounts are slow)
218+
- Linux: Mutagen disabled by default (native bind mounts are fast)
219+
220+
**Global config** (`~/.scdev/global-config.yaml`):
221+
```yaml
222+
mutagen:
223+
enabled: auto # auto, true, or false
224+
sync_mode: two-way-safe
225+
```
226+
227+
**Project config** (`.scdev/config.yaml`):
228+
```yaml
229+
mutagen:
230+
ignore:
231+
- var/cache
232+
- var/log
233+
- "*.log"
234+
```
235+
236+
**How it works:**
237+
1. On `scdev start`: Creates Docker volumes, starts containers with volumes instead of bind mounts, creates Mutagen sync sessions
238+
2. On `scdev stop`: Pauses sync sessions
239+
3. On `scdev down`: Terminates sync sessions, optionally removes sync volumes with `-v`
240+
241+
**CLI commands:**
242+
- `scdev mutagen status` - Show sync status for project
243+
- `scdev mutagen reset` - Recreate sync sessions (if stuck)
244+
- `scdev mutagen flush` - Wait for sync completion
245+
246+
**Naming convention:** `scdev-<project>-<service>` (e.g., `scdev-myshop-app`) - Mutagen only allows alphanumeric and hyphens
247+
248+
**Note:** Only directory bind mounts are synced via Mutagen. Single-file mounts remain as regular bind mounts.
249+
250+
**Note:** Ignored paths are NOT synced in either direction. This affects IDE autocomplete if `vendor/` or `node_modules/` are ignored.
251+
252+
## Additional Commands
253+
254+
### Logs
255+
```bash
256+
scdev logs [service] # View logs (defaults to first service)
257+
scdev logs -f app # Follow logs in real-time
258+
scdev logs --tail 50 app # Show last 50 lines
259+
```
260+
261+
### Restart
262+
```bash
263+
scdev restart # Stop + start the project
264+
```
265+
266+
### Open Shared Service UIs
267+
```bash
268+
scdev mail # Open Mailpit in browser
269+
scdev db # Open Adminer in browser
270+
scdev redis # Open Redis Insights in browser
271+
scdev docs # Open docs page in browser
272+
```
273+
274+
## Detailed Docs
275+
276+
- `planning/implementation-plan.md` - Full milestone details, acceptance criteria
277+
- `planning/scdev-project-briefing.md` - Original design doc (reference when needed)

0 commit comments

Comments
 (0)