Contributing
Prerequisites
- Go 1.26+
- Python 3.10+ with pip (compatibility tests)
- Docker (optional — Lambda runtime and integration tests)
pre-commit(optional but recommended)- Hugo extended 0.165+ (optional — only to preview this documentation as a site)
No C toolchain and no SQLite headers: the SQLite driver is pure Go, which is why
everything here builds with CGO_ENABLED=0.
Setup
git clone https://github.com/skyoo2003/devcloud.git
cd devcloud
make build # builds dist/devcloud and dist/codegen
make run # starts the server on port 4747Make Targets
| Command | Description |
|---|---|
make build | Build both binaries into dist/ — devcloud and codegen |
make run | Run the server from source (go run ./cmd/devcloud) |
make test | Run all Go tests with CGO_ENABLED=0 and -v |
make test-compat | Install tests/compatibility/requirements.txt and run the boto3 suite |
make codegen | Regenerate internal/generated/ from every model in smithy-models/ |
make codegen-s3 | Same, restricted to S3 — fast loop while editing templates |
make docker-build | Build the image from docker/Dockerfile as devcloud/devcloud |
make docker-run | Run that image on port 4747 with ./data mounted |
make docs-serve | Preview this documentation locally with Hugo |
make docs-build | Build the documentation site and check every internal link |
make clean | Delete dist/, data/, and the Hugo output in public/ and resources/ |
make changelog VERSION=vX.Y.Z | Batch and merge Changie fragments; VERSION is required |
make stats | Print registered service and operation counts |
Testing
make test # Go tests, CGO_ENABLED=0 — the same mode releases ship
make test-compat # Python/boto3 suite in tests/compatibility/You do not need a server running first. The devcloud_server session fixture
in conftest.py starts one via go run, on
a free port, against a temporary data directory it removes afterwards. Three
environment variables change that:
| Variable | Effect |
|---|---|
DEVCLOUD_EXTERNAL=1 | Connect to a server already running (e.g. in Docker) instead of starting one |
DEVCLOUD_BIN=<path> | Run a pre-built binary instead of go run — much faster |
DEVCLOUD_PORT=<port> | Use a fixed port instead of an arbitrary free one |
To run the suite directly:
cd tests/compatibility
pip install -r requirements.txt
pytest -vCode Generation
Never edit files in internal/generated/ — codegen overwrites them.
make codegen # all services
make codegen-s3 # one service| Piece | Where |
|---|---|
| Models | smithy-models/*.json |
| Sources | internal/codegen/source.go — ModelSource per format; SmithySource today |
| Generator | internal/codegen/generator.go + internal/codegen/templates/ |
| Output | internal/generated/{service}/ — types.go, router.go, errors.go, base_provider.go |
Providers parse the raw *http.Request themselves, so there is no generated
serializer or deserializer. See architecture.md.
Reviewing the weekly model sync
smithy-sync.yml refreshes all 194
vendored models every Monday and opens a pull request. The diff is whole-tree — a
measured refresh moved 93 models and 134 generated files — so do not try to read
it. Read the PR body instead: it is generated by scripts/model_churn.py and
lists which services gained or lost operations.
Three things to check, in order:
- Operations added or removed. These are the only changes that alter what DevCloud serves. Everything else is upstream reshaping traits or docs.
- A red
cirun on the published-figure gate. Expected, not a defect: new operations move the fidelity manifest, andcmd/devcloud/coverage_test.gofails untildocs/coverage.mdis re-derived. Correct the figures in the sync PR — never relax the gate to make it pass. codegen-driftandcompat. These must be green on their own. A redcodegen-driftmeans the committed output does not match the models; a redcompatmeans a real behavioural regression.
The in-job test result is printed at the top of the PR body. A failure there
with a clean codegen-drift almost always means item 2.
Adding a New AWS Service
- Add the Smithy model to
smithy-models/. - Run
make codegen— generates types, router, errors and stubs. - Implement the provider in
internal/services/<service>/provider.go. Start with the most commonly used operations; the generated base provider makes everything else returnNotImplementedError. - Implement the store in
store.go— SQLite for relational metadata, BadgerDB for key-value, in-memory for ephemeral, filesystem for blobs. - Register the plugin from an
init()inregister.go, and blank-import the package incmd/devcloud/imports.go. The interface contract, error convention and config keys are in plugin-api.md. - Wire startup and config —
cmd/devcloud/main.goandinternal/config/default.yaml. - Write tests — Go unit tests plus boto3 tests in
tests/compatibility/. - Document it — a page under
docs/services/for a core service.
internal/
├── generated/{service}/ # Auto-generated (DO NOT EDIT)
│ ├── types.go # Request/response structs
│ ├── router.go # Operation routing
│ ├── errors.go # Error types
│ └── base_provider.go # Stub (NotImplementedError)
│
└── services/{service}/ # Your implementation
├── provider.go # Service logic
├── store.go # Storage backend
└── register.go # Plugin registrationDocumentation
Everything under docs/ is read two ways: as plain markdown on github.com, and
as the site at https://skyoo2003.github.io/devcloud/. Hugo mounts the directory
rather than copying it, so both come from the same files.
That dual audience sets one rule: no front matter. GitHub renders a YAML
block as a metadata table above the page, so titles come from each document’s
H1 instead, and links stay plain and relative ([coverage](coverage.md#tiers))
rather than Hugo ref shortcodes.
Adding a page takes two steps:
- Write
docs/<name>.mdstarting with an# H1— that becomes its title. - Add it to
[menu.before]inhugo.toml. The sidebar is defined there because Hugo would otherwise sort pages alphabetically, and every entry needs its ownidentifier— entries without one collapse into a single link.
Then run make docs-build. Links that leave docs/ — to source files or to
root files like CONTRIBUTING.md — are rewritten to point at GitHub, which also
means an unresolvable link fails silently; scripts/check-site-links.py, which
make docs-build runs, is what catches it.
Code Style
- Standard Go conventions (
gofmt,go vet) - One responsibility per file; use existing services as patterns
- Errors follow the AWS shape (Code, Message, StatusCode) — see plugin-api.md
- New Go files start with
// SPDX-License-Identifier: Apache-2.0. Generated files keep theDO NOT EDITmarker on line 1 and the SPDX header on line 2. Thego-spdx-headerpre-commit hook adds it if missing.
Pre-commit hooks
pre-commit install
pre-commit run --all-files # optional: check the whole tree now.pre-commit-config.yaml runs go-spdx-header,
gofmt -l -w, go vet and go build on Go files — the last two with
CGO_ENABLED=0, so a contributor without a C toolchain still gets them. Python
under tests/ and scripts/ is handled by ruff. internal/generated/ and
smithy-models/ are excluded throughout.
Linting
The full linter is not in pre-commit; CI runs it separately
(lint.yml). Run it before opening a PR:
golangci-lint run --timeout=5mLicense of Contributions
DevCloud is licensed under the Apache License, Version 2.0. By submitting a contribution you agree that it will be licensed under the same terms. See LICENSE and NOTICE.