Thank you for your interest in contributing to CUDly! This document provides guidelines and instructions for contributing to the CLI component.
By participating in this project, you agree to maintain a respectful and inclusive environment. Be kind, constructive, and professional in all interactions.
- Search existing issues - Check if the bug has already been reported
- Create a detailed report including:
- CUDly version (
./cudly --help) - Go version (
go version) - Operating system and architecture
- Cloud provider and service affected
- Steps to reproduce
- Expected vs actual behavior
- Relevant logs (with sensitive data removed)
- CUDly version (
- Search existing issues - Your idea may already be proposed
- Open a feature request with:
- Clear description of the feature
- Use case and benefits
- Proposed implementation (if applicable)
- Any potential drawbacks
-
Fork the repository
-
Create a feature branch from
main:git checkout -b feature/your-feature-name
-
Make your changes following our coding standards
-
Write or update tests for your changes
-
Run the test suite to ensure everything passes
-
Commit with clear messages following our commit conventions
-
Push to your fork and submit a Pull Request
- Go 1.26.6 or later (the floor set by the
godirective ingo.mod) - Git
# Clone your fork
git clone https://github.com/YOUR_USERNAME/cloud-commitments-cli.git
cd cloud-commitments-cli
# Add upstream remote
git remote add upstream https://github.com/LeanerCloud/cloud-commitments-cli.git
# Install dependencies
go mod download
# Build
make build
# Run the unit tests
make test-unitThe repo ships a go.work that lists only this repository's own module. The shared libraries and providers are consumed at the versions pinned in go.mod, so there is nothing else to set up for a standard clone. When you are working across multiple git worktrees simultaneously, gopls needs each worktree's module added to the workspace or it flags every file in the sibling trees with BrokenImport / undefined: <Type>.
Do not edit the committed go.work for local paths -- they vary per
developer and per session.
Instead, create a go.work.local next to go.work (it is gitignored): start
from a copy of the committed go.work and append your active worktrees:
// go.work.local -- gitignored, developer-local
// Keep this `go` line at or above the modules' own directive, otherwise the
// workspace is rejected. Copy it from the committed go.work.
go 1.26.6
use (
.
../.worktrees/cloud-commitments-cli/fix-516
../.worktrees/cloud-commitments-cli/feat-something
)Then point gopls at it by setting GOWORK before launching your editor, or by
symlinking it over go.work temporarily:
# Option A: set GOWORK in your shell profile or editor launcher
export GOWORK="$PWD/go.work.local"
# Option B: create go.work.local and let gopls auto-discover it
# (gopls respects GOWORK when set; otherwise it walks up for go.work)After adding or removing a worktree, update go.work.local to match:
# Quick regeneration from git worktree list (space-safe: keeps full paths,
# adds one -use entry per worktree; skips the main checkout on line 1)
git worktree list --porcelain | sed -n 's/^worktree //p' | tail -n +2 |
while IFS= read -r wt; do go work edit -use "$wt"; doneThe committed go.work (listing only this repository's own modules) keeps
go vet ./..., go test ./..., and CI clean for everyone without requiring
any local setup. Note that go build ./... is not a valid way to build this
repo: cmd/ is the only main package, and Go's default output name for a
lone main package collides with the cmd directory itself. Use make build
or go build -o cudly ./cmd instead (see "Getting Started" above).
# Run the unit tests
make test-unit
# The same suite, invoked directly
go test -short -race ./...
# Run tests with coverage
go test -cover ./...
# Run tests for a specific package
go test ./cmd/...
# Run tests with verbose output
go test -v ./...
# Run a specific test
go test -run TestFunctionName ./path/to/packageWe aim to maintain the following minimum test coverage:
| Package | Minimum Coverage |
|---|---|
| CLI commands | 60% |
- Follow the Effective Go guidelines
- Use
gofmtto format code - Use
golintandgo vetto catch issues - Keep functions focused and reasonably sized
- Write clear, self-documenting code
- Use CamelCase for exported names, camelCase for unexported
- Use meaningful, descriptive names
- Interfaces describing behavior should end in
-er(e.g.,Reader,Writer) - Test files:
*_test.go - Mock implementations: prefix with
mock
- All exported functions, types, and packages must have doc comments
- Use complete sentences starting with the name being documented
- Include usage examples for complex functionality
- Keep comments up to date with code changes
- Always handle errors explicitly
- Wrap errors with context using
fmt.Errorf("context: %w", err) - Use custom error types for domain-specific errors
- Never ignore errors silently
- Write table-driven tests where appropriate
- Use interfaces and dependency injection for testability
- Mock external dependencies (AWS/Azure/GCP SDKs)
- Test both success and error paths
- Include edge cases in test coverage
cloud-commitments-cli/
├── cmd/ # CLI entry point, commands, and helpers
├── docs/ # CLI documentation
├── scripts/ # Repository hook and helper scripts
├── go.mod # Pins the shared modules from cloud-commitments-go
└── Makefile # build, test, vet, and lint targets
Service clients live in github.com/LeanerCloud/cloud-commitments-go. In this
repository:
- Add the service's command and flags in
cmd/ - Reuse the service client from the pinned provider module
- Register the service in the CLI's service selection
- Write comprehensive tests
- Update
docs/
Provider implementations live in github.com/LeanerCloud/cloud-commitments-go
(providers/aws, providers/azure, providers/gcp). Open the change there.
This repository consumes providers at the versions pinned in go.mod, so
bumping that pin is the only change needed here.
type(scope): brief description
Longer description if needed. Explain what and why,
not how (the code shows how).
Fixes #123
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Formatting, missing semicolons, etc.refactor: Code change that neither fixes a bug nor adds a featureperf: Performance improvementtest: Adding or updating testschore: Build process, dependencies, etc.
feat(aws): add MemoryDB reserved node support
Implements purchase and recommendation fetching for
Amazon MemoryDB reserved nodes.
Fixes #42
fix(azure): handle subscription pagination correctly
The previous implementation missed subscriptions after
the first page. Now properly iterates all pages.
- Update documentation for any user-facing changes
- Add or update tests for your changes
- Ensure all tests pass before submitting
- Fill out the PR template completely
- Request review from maintainers
- Address feedback promptly and constructively
- Code follows project style guidelines
- Tests added/updated and passing
- Documentation updated
- Commit messages follow conventions
- No sensitive data in code or commits
- Changes are backwards compatible (or breaking changes documented)
This repository has no known_issues/ directory. Deferred work found while
reviewing a change here belongs in this repository's GitHub issues. The
cross-component sweep, which covers known_issues/ in the platform repository,
is documented there.
Each file must begin with a # Known Issues: <topic> heading followed by an
audit-status line:
> **Audit status (<YYYY-MM-DD>):** `<N> needs triage · <M> resolved`
Subsequent sections use ## SEVERITY: Short title (e.g. ## MEDIUM: ...) and
include at minimum: Files (affected paths), Description, Why
deferred, and Status.
- Tech debt or a follow-up bug is discovered during a PR review but is explicitly out of scope for that PR.
- A test is marked flaky and a root-cause fix is deferred.
- A deliberate deferral is made (e.g. "fix after the current refactor lands").
Create a new file known_issues/<NN>_<slug>.md (sequential number, lowercase
slug) and open a corresponding GitHub issue so it can be tracked and closed.
An entry is stale when its corresponding GitHub issue is closed OR when the
entry has had no recurrence for more than 6 months and no open issue
references it. Do not delete stale files; move them to known_issues/resolved/
so the rationale is preserved for future readers.
Any contributor working in a file covered by a known_issues/ doc should
check whether that doc's referenced issue is still open; archive it if not.
A dedicated sweep over the whole directory should happen:
- At the start of each sprint (or monthly if sprints are not used).
- After any PR that explicitly closes multiple issues.
- When a new contributor is onboarding and doing a codebase walkthrough.
To perform a sweep:
# List docs referencing a specific issue number
grep -rl "#<issue-number>" known_issues/
# Cross-check all referenced issues in bulk
grep -h "closes #\|Fixes #\|#[0-9]\+" known_issues/*.md \
| grep -oE '#[0-9]+' | sort -u \
| xargs -I{} gh issue view {} --json state,number,title --jq '[.number,.state,.title]'Move resolved docs to known_issues/resolved/:
git mv known_issues/<file>.md known_issues/resolved/Include the archive in the same PR that closes the underlying issue, or in a
dedicated chore(docs): archive resolved known_issues commit.
Do not report security vulnerabilities through public issues.
Instead, please email security concerns to the maintainers directly. Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Never commit credentials or secrets
- Use environment variables for sensitive configuration
- Validate all external input
- Follow least-privilege principles
- Keep dependencies updated
We welcome contributions in these areas:
- Additional AWS services (Lambda, DynamoDB, etc.)
- Azure service implementations
- GCP service implementations
- Improved error messages and user experience
- Enhanced reporting and analytics
- Terraform/CloudFormation integration
- Web UI dashboard
- Performance optimizations
- Usage tutorials and guides
- Architecture documentation
- API documentation
- Translation to other languages
- Issues: Open a GitHub issue for bugs or features
- Discussions: Use GitHub Discussions for questions
- Documentation: Check the README and code comments
By contributing to CUDly, you agree that your contributions will be licensed under the Open Software License 3.0 (OSL-3.0).
This means:
- Your contributions can be used commercially
- Derivative works must also be OSL-3.0 licensed
- You grant a patent license for your contributions
- Attribution must be maintained
Thank you to all contributors who help make CUDly better! Your time and expertise are greatly appreciated.