Contributing to SnmpKit
Thank you for your interest in contributing to SnmpKit! This document provides guidelines and information for contributors.
Table of Contents
- Code of Conduct
- Getting Started
- Development Setup
- Contributing Process
- Code Standards
- Testing Guidelines
- Documentation
- Submitting Changes
- Release Process
- Getting Help
Code of Conduct
This project adheres to a code of conduct that we expect all contributors to follow. Please be respectful, inclusive, and constructive in all interactions.
Our Standards
- Use welcoming and inclusive language
- Be respectful of differing viewpoints and experiences
- Gracefully accept constructive criticism
- Focus on what is best for the community
- Show empathy towards other community members
Getting Started
Prerequisites
- Elixir 1.14+ and OTP 25+
- Git
- A GitHub account
- Basic understanding of SNMP concepts
- Familiarity with Elixir/OTP development
Types of Contributions
We welcome various types of contributions:
- Bug Reports - Help us identify and fix issues
- Feature Requests - Suggest new functionality
- Code Contributions - Bug fixes, new features, improvements
- Documentation - Improve docs, examples, guides
- Testing - Add test cases, improve test coverage
- Performance - Optimization and benchmarking
- Device Profiles - Add support for new device types
Development Setup
Clone the Repository
git clone https://github.com/awksedgreep/snmpkit.git
cd snmpkit
Install Dependencies
mix deps.get
Verify Setup
# Run the test suite
mix test
# Generate documentation
mix docs
# Check code formatting
mix format --check-formatted
# Run static analysis
mix credo
Development Tools
We recommend using these tools for development:
- Editor: VS Code with ElixirLS extension
- Formatter: Built-in
mix format
- Linter: Credo for code analysis
- Testing: ExUnit with coverage reporting
- Docs: ExDoc for documentation generation
Contributing Process
1. Create an Issue
Before starting work, please create an issue to discuss:
- Bug reports with reproduction steps
- Feature requests with use cases
- Performance improvements with benchmarks
- Documentation improvements
2. Fork and Branch
# Fork the repository on GitHub
# Clone your fork
git clone https://github.com/yourusername/snmpkit.git
cd snmpkit
# Create a feature branch
git checkout -b feature/your-feature-name
3. Make Changes
- Follow our code standards
- Add tests for new functionality
- Update documentation as needed
- Ensure all tests pass
4. Test Your Changes
# Run all tests
mix test
# Run with coverage
mix test --cover
# Run integration tests
mix test --include integration
# Run performance tests
mix test --include performance
5. Submit a Pull Request
- Push your branch to your fork
- Create a pull request with a clear description
- Reference any related issues
- Ensure CI passes
Code Standards
Elixir Style Guide
We follow the Elixir Style Guide with these specific preferences:
Formatting
# Use mix format - it's configured in .formatter.exs
mix format
Naming Conventions
# Modules: PascalCase
defmodule SnmpKit.MIB.Resolver do
end
# Functions: snake_case
def resolve_oid(name) do
end
# Variables: snake_case
result_set = []
# Constants: SCREAMING_SNAKE_CASE
@default_timeout 5_000
Documentation
defmodule SnmpKit.Example do
@moduledoc """
Brief module description.
Longer description with examples if needed.
## Examples
iex> SnmpKit.Example.function()
{:ok, result}
"""
@doc """
Brief function description.
## Parameters
- `param1` - Description of parameter
- `param2` - Description of parameter
## Returns
- `{:ok, result}` on success
- `{:error, reason}` on failure
## Examples
iex> SnmpKit.Example.function("test")
{:ok, "result"}
"""
@spec function(String.t()) :: {:ok, String.t()} | {:error, atom()}
def function(param1) do
{:ok, param1}
end
end
Error Handling
# Use tagged tuples for function returns
def get_value(key) do
case fetch_value(key) do
{:ok, value} -> {:ok, value}
{:error, :not_found} -> {:error, :not_found}
{:error, reason} -> {:error, reason}
end
end
# Use with statements for complex operations
def complex_operation(data) do
with {:ok, parsed} <- parse_data(data),
{:ok, validated} <- validate_data(parsed),
{:ok, result} <- process_data(validated) do
{:ok, result}
else
{:error, reason} -> {:error, reason}
end
end
Pattern Matching
# Prefer pattern matching over conditionals
def handle_response({:ok, %{status: 200, body: body}}) do
process_success(body)
end
def handle_response({:ok, %{status: status}}) when status >= 400 do
{:error, :http_error}
end
def handle_response({:error, reason}) do
{:error, reason}
end
Code Organization
Module Structure
defmodule SnmpKit.Example do
@moduledoc "..."
# Behaviours
@behaviour SomeBehaviour
# Use statements
use GenServer
# Import statements
import SomeModule
# Alias statements
alias SnmpKit.Other.Module
# Module attributes
@default_timeout 5_000
# Types
@type example_type :: atom() | String.t()
# Public API
def public_function do
end
# Private functions
defp private_function do
end
end
File Organization
lib/
├── snmpkit.ex # Main module with convenience functions
├── snmpkit/
│ ├── snmp/ # SNMP operations
│ │ ├── client.ex
│ │ ├── engine.ex
│ │ └── formatter.ex
│ ├── mib/ # MIB management
│ │ ├── resolver.ex
│ │ ├── compiler.ex
│ │ └── loader.ex
│ └── sim/ # Device simulation
│ ├── device.ex
│ └── profile_loader.ex
Testing Guidelines
Test Organization
defmodule SnmpKit.ExampleTest do
use ExUnit.Case, async: true
alias SnmpKit.Example
describe "function_name/1" do
test "handles valid input" do
assert {:ok, result} = Example.function_name("valid")
assert result == "expected"
end
test "handles invalid input" do
assert {:error, :invalid} = Example.function_name("invalid")
end
test "handles edge cases" do
assert {:ok, ""} = Example.function_name("")
assert {:error, :invalid} = Example.function_name(nil)
end
end
end
Test Categories
Use tags to categorize tests:
@moduletag :unit # Fast unit tests
@moduletag :integration # Tests with external dependencies
@moduletag :performance # Performance benchmarks
@moduletag :docsis # DOCSIS-specific tests
Test Data
- Use ExUnit setup for test data
- Create realistic test fixtures
- Use property-based testing for complex scenarios
defmodule SnmpKit.PropertyTest do
use ExUnit.Case
use PropCheck
property "OID resolution is consistent" do
forall oid <- valid_oid() do
case SnmpKit.MIB.resolve(oid) do
{:ok, resolved} -> is_list(resolved)
{:error, _} -> true
end
end
end
end
Coverage Requirements
- Maintain >95% test coverage
- Test both success and error paths
- Include edge cases and boundary conditions
- Test concurrent operations where applicable
Documentation
Code Documentation
- All public modules must have
@moduledoc
- All public functions must have
@doc
- Include
@spec
for all public functions - Provide examples in doctests
Guides and Tutorials
- Update relevant guides when adding features
- Include practical examples
- Explain the "why" not just the "how"
- Keep examples up to date
API Documentation
- Use clear, concise language
- Include parameter descriptions
- Document return values and error conditions
- Provide usage examples
Submitting Changes
Pull Request Guidelines
Title Format
Use conventional commit format:
feat: add new SNMP operation
fix: resolve OID resolution bug
docs: update MIB guide
test: add performance benchmarks
refactor: improve error handling
Description Template
## Summary
Brief description of changes
## Changes
- List of specific changes
- Include any breaking changes
## Testing
- How the changes were tested
- New test cases added
## Documentation
- Documentation updates made
- Examples added/updated
## Related Issues
Fixes #123
Closes #456
Checklist
Before submitting, ensure:
- [ ] Code follows style guidelines
- [ ] Tests pass locally
- [ ] New tests added for new functionality
- [ ] Documentation updated
- [ ] No breaking changes (or clearly marked)
- [ ] Commit messages follow conventional format
- [ ] Branch is up to date with main
Review Process
- Automated Checks - CI runs tests and checks
- Code Review - Maintainers review code
- Discussion - Address any feedback
- Approval - At least one maintainer approval
- Merge - Squash and merge to main
After Your PR is Merged
- Delete your feature branch
- Update your fork's main branch
- Consider contributing more!
Release Process
Versioning
We follow Semantic Versioning:
- MAJOR - Breaking changes
- MINOR - New features, backward compatible
- PATCH - Bug fixes, backward compatible
Release Workflow
- Update version in
mix.exs
- Update
CHANGELOG.md
- Create release PR
- Tag release after merge
- Publish to Hex.pm
- Update documentation
Getting Help
Communication Channels
- GitHub Issues - Bug reports, feature requests
- GitHub Discussions - General questions, ideas
- Email - Security issues only
Documentation Resources
Mentorship
New contributors are welcome! We're happy to help you get started:
- Look for "good first issue" labels
- Ask questions in discussions
- Start with documentation improvements
- Join our community
Recognition
Contributors are recognized in:
- CHANGELOG.md for each release
- README.md contributors section
- GitHub contributors graph
- Special recognition for significant contributions
Thank you for contributing to SnmpKit! Your efforts help make SNMP management better for everyone in the Elixir community.