Thanks for helping out. This page covers the dev setup and how changes get merged.
- Fork the repository.
- Clone your fork:
git clone https://github.com/<your-username>/cloudemu.git cd cloudemu
- Create a feature branch from
development:git checkout development git checkout -b feature/your-feature-name
Requirements:
- Go 1.25.0+
- golangci-lint v2
go build ./... # compile all packages
go test ./... # run all tests
go vet ./... # static analysis- Max line length: 140 characters
- Max cyclomatic complexity: 10
- Max function length: 100 lines / 50 statements
- No magic numbers. Use named constants.
- Import order: stdlib, third-party, local module (enforced by
gci) - Thread safety: all mock implementations must use
sync.RWMutex
Run the linter before you open a PR:
golangci-lint run --timeout=9m ./...Fix every issue. If you need a //nolint directive, add a comment explaining why.
- Add types and methods to the driver interface (
services/<service>/driver/driver.go). - Implement them in all 3 providers (AWS, Azure, GCP).
- Wire them through the portable API layer (
services/<service>/<service>.go). - Add integration tests to
cloudemu_test.go. - Add unit tests to each provider's test file.
- Run the linter and the full test suite.
- Create the driver interface in
services/<service>/driver/driver.go. - Create provider implementations in
providers/{aws,azure,gcp}/<service>/. - Add a field to each Provider struct.
- Initialize it in each
New()factory. - Add the portable API wrapper.
- Add tests.
- All 3 providers (AWS, Azure, GCP) must implement the same behavior.
- Use
cerrors.New()/cerrors.Newf()for error codes. - Use
config.FakeClockfor deterministic time in tests. - Use
memstore.Store[V]for in-memory storage. - Use
idgenfor cloud-native IDs.
- Make sure the tests pass:
go test ./... - Make sure the linter passes:
golangci-lint run --timeout=9m ./... - Push your branch and open a PR against
development. - In the PR description, say what changed and why.
- Use GitHub Issues for bugs and feature requests.
- For bugs, include steps to reproduce.
- Add the labels that apply (aws, azure, gcp, enhancement, bug).
Pushing a v* tag triggers .github/workflows/release.yml. It runs
GoReleaser, which builds cross-platform binaries, publishes a GitHub Release with
checksums.txt, and pushes a Homebrew cask to github.com/stackshy/homebrew-tap
(this is what makes brew install stackshy/tap/cloudemu work).
One-time setup for the Homebrew push:
- The public tap repo
github.com/stackshy/homebrew-tapmust exist. - Add a repository secret named
HOMEBREW_TAP_TOKEN: a Personal Access Token with write access to the tap repo. GoReleaser uses it to commit the cask. Without it, the release still publishes and only the Homebrew push is skipped.
Check config changes locally before tagging:
go run github.com/goreleaser/goreleaser/v2@latest check
go run github.com/goreleaser/goreleaser/v2@latest release --snapshot --clean --skip=publishBy contributing, you agree that your contributions will be licensed under the MIT License.