Thank you for your interest in contributing to dtctl! This document provides guidelines and instructions for contributing.
- Code of Conduct
- Getting Started
- Development Setup
- How to Contribute
- Pull Request Process
- Coding Standards
- Testing Requirements
- Commit Messages
- Reporting Bugs
- Suggesting Features
This project adheres to a Code of Conduct that all contributors are expected to follow. Please read CODE_OF_CONDUCT.md before contributing.
- Go 1.24 or later
- Git
- A Dynatrace environment (for integration testing)
-
Fork and clone the repository:
git clone https://github.com/dynatrace-oss/dtctl.git cd dtctl -
Install dependencies:
go mod download
-
Build the project:
make build
-
Run tests:
make test -
Install development tools:
# Install linters go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest # Install vulnerability scanner go install golang.org/x/vuln/cmd/govulncheck@latest
- Report bugs - Help us identify and fix issues
- Suggest features - Share ideas for improvements
- Write documentation - Improve guides, examples, and API docs
- Submit code - Fix bugs or implement new features
- Review pull requests - Help review and test contributions
- Check the issue tracker
- Look for issues labeled
good first issueorhelp wanted - Ask in discussions if you're unsure where to start
- Check existing issues and PRs to avoid duplicate work
- Create an issue to discuss major changes before implementing
- Fork the repository and create a feature branch
-
Create a feature branch:
git checkout -b feature/your-feature-name
-
Make your changes:
- Write clear, focused commits
- Add tests for new functionality
- Update documentation as needed
- Follow coding standards (see below)
-
Test your changes:
# Run all tests make test # Run linters make lint # Check test coverage make coverage
-
Push to your fork:
git push origin feature/your-feature-name
-
Create a pull request:
- Use a clear, descriptive title
- Reference any related issues
- Describe what changed and why
- Include examples if applicable
Your pull request must:
- ✅ Pass all CI checks (tests, linting, security scans)
- ✅ Maintain or improve test coverage (minimum 70%)
- ✅ Include tests for new functionality
- ✅ Update documentation if behavior changes
- ✅ Follow the project's coding standards
- ✅ Have clear commit messages
- ✅ Be up-to-date with the main branch
- Maintainers will review your PR within 5 business days
- Address any feedback or requested changes
- Once approved, a maintainer will merge your PR
- Your contribution will be included in the next release
Follow the official Go Code Review Comments and Effective Go.
File Organization:
- Keep files under 500 lines
- One package per directory
- Group related functionality together
Naming:
- Use descriptive names (avoid abbreviations except for common ones)
- Follow Go conventions:
camelCasefor unexported,PascalCasefor exported - Interfaces: use
-ersuffix (e.g.,Handler,Executor)
Error Handling:
- Always check errors
- Wrap errors with context using
fmt.Errorf("context: %w", err) - Return errors rather than logging and continuing
Comments:
- Add package-level comments for all packages
- Document all exported functions, types, and constants
- Use
//for comments, not/* */ - Explain "why" not "what" for complex logic
Code Organization:
package example
// Imports (standard library first, then third-party, then internal)
import (
"context"
"fmt"
"github.com/spf13/cobra"
"github.com/dynatrace/dtctl/pkg/client"
)
// Constants
const defaultTimeout = 30 * time.Second
// Variables
var ErrNotFound = errors.New("resource not found")
// Types
type Handler struct { ... }
// Functions
func NewHandler() *Handler { ... }- Use
gofmtto format code (enforced in CI) - Use
goimportsto organize imports - Maximum line length: 120 characters
- Minimum: 70% overall coverage
- New code: 80% coverage for new packages
- Critical packages: 90% coverage for
pkg/client,pkg/config
Test file naming: *_test.go (e.g., client_test.go)
Test function naming: TestFunctionName_Scenario (e.g., TestNewClient_InvalidURL)
Test structure (use table-driven tests):
func TestHandler_Get(t *testing.T) {
tests := []struct {
name string
id string
want *Resource
wantErr bool
}{
{
name: "valid resource",
id: "123",
want: &Resource{ID: "123"},
wantErr: false,
},
{
name: "not found",
id: "invalid",
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test implementation
})
}
}- Unit tests: Test individual functions in isolation
- Integration tests: Test component interactions (use
httptestfor API mocking) - E2E tests: Test complete workflows (in
test/e2e/)
# Run all tests
make test
# Run tests with coverage
make coverage
# Run specific package tests
go test ./pkg/client/...
# Run specific test
go test -run TestClientNew ./pkg/client/
# Run tests with race detection
go test -race ./...<type>: <subject>
<body>
<footer>
feat: New featurefix: Bug fixdocs: Documentation changestest: Adding or updating testsrefactor: Code refactoring (no functional changes)perf: Performance improvementschore: Maintenance tasks (dependencies, tooling)ci: CI/CD changes
feat: add support for OpenPipeline resources
Implement get, create, update, and delete operations for OpenPipeline
configurations. Includes CLI commands and resource handler.
Closes #123
fix: handle pagination correctly in document listing
Previously, only the first page of results was returned when listing
documents. Now correctly follows pagination tokens to fetch all results.
Fixes #456
- Use imperative mood ("add feature" not "added feature")
- Keep subject line under 50 characters
- Capitalize subject line
- No period at the end of subject line
- Separate subject from body with blank line
- Wrap body at 72 characters
- Explain what and why, not how
- Check if the bug has already been reported
- Verify it's reproducible on the latest version
- Gather relevant information (version, OS, configuration)
When reporting a bug, include:
- Description: Clear description of the issue
- Steps to Reproduce:
1. Run `dtctl get workflows` 2. Observe error message - Expected Behavior: What you expected to happen
- Actual Behavior: What actually happened
- Environment:
- dtctl version (
dtctl version) - OS and version
- Go version (if building from source)
- dtctl version (
- Additional Context: Logs, screenshots, or other relevant information
When suggesting a feature, include:
- Problem Statement: What problem does this solve?
- Proposed Solution: How should it work?
- Alternatives Considered: Other approaches you considered
- Use Cases: Real-world scenarios where this would be useful
- Implementation Ideas: Technical approach (optional)
# Build the binary
make build
# Run tests
make test
# Run linters
make lint
# Generate coverage report
make coverage
# Run security scans
make security-scan
# Build for all platforms
make build-all
# Clean build artifacts
make cleanAll pull requests must pass:
- Tests: All tests must pass on Linux, macOS, and Windows
- Linting:
golangci-lintmust pass with zero errors - Security:
govulncheckmust find no vulnerabilities - Coverage: Overall coverage must be ≥70%
- Questions: Use GitHub Discussions
- Bugs: Open an issue
- Security: See SECURITY.md
By contributing to dtctl, you agree that your contributions will be licensed under the Apache License 2.0.
Thank you for contributing to dtctl! 🎉