Thank you for your interest in contributing to the Hypercerts CLI! This document provides guidelines and instructions for contributing.
- Go 1.25 or later
- Git
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/hypercerts-cli cd hypercerts-cli - Install dependencies:
go mod download
- Build and test:
make build make test
feature/- New featuresfix/- Bug fixesdocs/- Documentation updatesrefactor/- Code refactoring
-
Create a new branch from
main:git checkout -b feature/your-feature-name
-
Make your changes following our code style (see below)
-
Run tests and linting:
make test make lint make fmt -
Commit your changes with a clear message:
git commit -m "Add feature: description of changes" -
Push to your fork and open a Pull Request
Three groups separated by blank lines: stdlib, third-party, local.
import (
"context"
"fmt"
"github.com/urfave/cli/v3"
"github.com/GainForest/hypercerts-cli/internal/atproto"
)| Element | Convention | Example |
|---|---|---|
| Files | lowercase_underscores.go |
activity.go, util_test.go |
| Exported types/funcs | PascalCase |
CreateRecord, AuthSession |
| Unexported funcs | camelCase |
runActivityCreate, requireAuth |
| CLI actions | run + CommandName |
runAccountLogin, runActivityEdit |
| Constants | PascalCase |
CollectionActivity |
| Errors | Err prefix |
ErrNoAuthSession |
Always write to cmd.Root().Writer for testability:
w := cmd.Root().Writer
fmt.Fprintf(w, "Created record: %s\n", uri)// Wrap errors with context
return fmt.Errorf("failed to create record: %w", err)
// Use sentinel errors at package level
var ErrNoAuthSession = errors.New("no auth session found")-
Add NSID constant to
internal/atproto/collections.go:CollectionNewType = "org.hypercerts.claim.newType"
-
Create command file
cmd/newtype.gowith:type newTypeOption struct { ... }for menu displayfetchNewTypes()to list recordsselectNewType()for interactive selection (if needed)runNewTypeCreate/Edit/Delete/List()CLI actions
-
Add command definition to
cmd/root.go:- Add
cmdNewTypevariable - Wire into
BuildApp()Commands list
- Add
-
Add tests to
cmd/newtype_test.go -
Update documentation:
- Add section to README.md
- Update AGENTS.md command tree
# All tests
make test
# With race detector
make test-race
# Single test
go test -v -run TestFunctionName ./cmd/...
# Tests in a package
go test -v ./internal/menu/...- Use table-driven tests for validation functions
- Test both interactive and non-interactive code paths
- Use
bytes.Bufferto capture CLI output - Use
t.TempDir()for file system tests
Example:
func TestMyFunction(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"valid_input", "test", "expected"},
{"empty_input", "", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := myFunction(tt.input)
if got != tt.want {
t.Errorf("myFunction(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}- Tests pass (
make test) - Code is formatted (
make fmt) - Linting passes (
make lint) - Documentation is updated if needed
- Commit messages are clear and descriptive
Include:
- What the change does
- Why the change is needed
- Any breaking changes
- Related issues (if any)
- PRs require at least one approval
- All CI checks must pass
- Address review feedback promptly
- Squash commits before merging if needed
When reporting bugs, please include:
- Go version (
go version) - Operating system
- Steps to reproduce
- Expected vs actual behavior
- Error messages (if any)
Feel free to open an issue for questions or discussions about the project.
By contributing, you agree that your contributions will be licensed under the same license as the project.