13 KiB
13 KiB
Dokku Plugin Style Guide
This document outlines the best practices and conventions for developing high-quality Dokku plugins, based on the patterns used in popular official plugins like dokku-postgres, dokku-redis, dokku-letsencrypt, and others.
Plugin Types
Dokku plugins generally fall into three main categories, each with its own patterns and considerations:
1. Service Plugins (e.g., dokku-postgres, dokku-redis)
- Manage long-running services (databases, caches, etc.)
- Include full lifecycle management (create, destroy, backup, restore)
- Handle data persistence and migrations
- Support linking to applications
- Examples: PostgreSQL, Redis, MySQL, MongoDB
2. Utility Plugins (e.g., dokku-letsencrypt, dokku-http-auth)
- Add specific functionality to Dokku
- Often integrate with external services
- May run on schedules or triggers
- Examples: SSL certificates, authentication, monitoring
3. Core Plugins (e.g., dokku-postgres, dokku-redis)
- Provide fundamental infrastructure services
- Often bundled with Dokku
- Handle core functionality like networking, storage, etc.
- Examples: Network, Storage, Scheduler
Table of Contents
- Project Structure
- File Organization
- Code Style
- Testing
- Documentation
- Versioning
- CI/CD
- Common Patterns
- Best Practices
Project Structure
Dokku plugins follow a consistent structure that varies slightly based on the plugin type. Here's a comprehensive directory structure that covers all plugin types:
.
├── .github/ # GitHub-specific files
│ ├── workflows/ # GitHub Actions workflows
│ │ ├── ci.yml # Continuous Integration
│ │ └── release.yml # Release automation
│ └── dependabot.yml # Dependency updates
│
├── docs/ # Documentation
│ ├── README.md # Main documentation
│ ├── commands/ # Command references
│ └── examples/ # Usage examples
│
├── scripts/ # Utility scripts (optional)
│ └── setup_*.sh # Setup/configuration scripts
│
├── subcommands/ # Plugin subcommands (one file per subcommand)
│ ├── create # Service creation
│ ├── destroy # Service teardown
│ ├── backup # Data backup
│ └── ... # Other commands
│
├── tests/ # Test files
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ ├── test_helper.bash # Test utilities
│ └── setup.sh # Test setup
│
├── templates/ # Configuration templates (optional)
│ └── *.conf.sigil # Sigil templates for configs
│
├── .editorconfig # Editor configuration
├── .gitignore # Git ignore rules
├── Dockerfile # Development container
├── Makefile # Build and test tasks
├── plugin.toml # Plugin metadata
├── commands # Plugin command definitions
├── common-functions # Shared shell functions
├── help-functions # Help text generation
└── README.md # Project overview
Key Files Explained:
-
plugin.toml
- Required for all plugins
- Defines plugin metadata and configuration
- Example:
[plugin] description = "Postgres service plugin" version = "1.0.0" [plugin.config] # Default configuration values "docker-options" = "--restart=on-failure:10"
-
commands
- Defines the main plugin commands
- Maps commands to their implementations
- Example:
postgres:create postgres-create postgres:destroy postgres-destroy
-
subcommands/
- One file per subcommand
- Naming:
plugin-command(e.g.,postgres-create) - Each file should be executable and include help text
-
tests/
- BATS test files
- Mirror the command structure
- Include both unit and integration tests
File Organization
Core Files
-
plugin.toml
- Contains plugin metadata and configuration
- Defines plugin name, version, and dependencies
- Example:
[plugin] description = "Postgres service plugin" version = "1.15.0" [plugin.config] "docker-options" = "--restart=on-failure:10"
-
Makefile
- Standard build and test targets
- Common targets:
build,test,lint,install - Example:
.PHONY: test test: @bats tests/
-
Dockerfile
- Defines the development environment
- Includes all necessary build tools and dependencies
Subcommands
- Each subcommand is a separate file in the
subcommands/directory - Naming convention:
subcommands/<command>-<subcommand> - Example:
subcommands/service-create,subcommands/service-logs
Documentation
- Comprehensive README.md with:
- Installation instructions
- Basic usage examples
- Available commands
- Configuration options
- Troubleshooting
Code Style
Shell Scripting
- Use
#!/usr/bin/env bashfor portability - Follow Google's Shell Style Guide
- Use
localfor function-scoped variables - Quote all variables to prevent word splitting
- Use
[[for tests instead of[ - Example:
#!/usr/bin/env bash set -eo pipefail my_function() { local var1="value1" local var2="value2" if [[ "$var1" == "$var2" ]]; then echo "Values are equal" fi }
Error Handling
- Use
set -eo pipefailat the start of scripts - Provide meaningful error messages
- Use
trapfor cleanup operations - Example:
cleanup() { rm -f "$TEMP_FILE" } trap cleanup EXIT
Testing
Test Structure
- Use bats-core for testing
- Organize tests by functionality
- Follow naming convention:
tests/<feature>_test.bats - Example test file:
#!/usr/bin/env bats load 'test_helper/bats-support/load' load 'test_helper/bats-assert/load' setup() { # Test setup code } teardown() { # Test teardown code } @test "service create should succeed" { run dokku postgres:create test-db assert_success assert_output --partial "PostgreSQL container created: test-db" }
Test Coverage
- Test all subcommands
- Include error cases
- Test edge cases
- Mock external dependencies
- Use test fixtures for complex data
Documentation
Command Help
- Include help text for all commands
- Use
dokku <plugin>:help <command>pattern - Document all options and arguments
- Example:
help() { cat <<EOF Usage: dokku postgres:create <name> [options] Create a new PostgreSQL service. Options: --config-opt KEY=VALUE Set configuration option --image IMAGE Use custom Docker image EOF }
Man Pages
- Include man pages for complex commands
- Use
ronnor similar tool to generate man pages from markdown - Example:
docs/man/dokku-postgres-create.1.ronn
Versioning
- Follow Semantic Versioning
- Update version in
plugin.toml - Create GitHub releases with changelog
- Tag releases with
vprefix (e.g.,v1.0.0)
CI/CD
GitHub Actions
- Run tests on push and pull requests
- Lint shell scripts with ShellCheck
- Build and test on multiple platforms
- Example workflow:
name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run tests run: make test - name: Lint shell scripts run: shellcheck -x scripts/*
Release Process
- Update version in
plugin.toml - Update
CHANGELOG.md - Create git tag
- Push tag to trigger release
- GitHub Actions will publish the release
Common Patterns
Service Management
# Start service
dokku postgres:start my-db
# Stop service
dokku postgres:stop my-db
# View logs
dokku postgres:logs my-db
Data Management
# Create backup
dokku postgres:backup my-db
# Restore from backup
dokku postgres:restore my-db < backup.dump
# Export data
dokku postgres:export my-db > data.sql
Linking Services
# Link service to app
dokku postgres:link my-db my-app
# Unlink service
dokku postgres:unlink my-db my-app
Best Practices
Core Principles
- Idempotency: All commands should be idempotent (running them multiple times has the same effect as running them once)
- Error Handling:
- Provide clear, actionable error messages
- Include error codes for programmatic handling
- Clean up resources on failure
- Documentation:
- Document all commands with examples
- Keep README and help text up-to-date
- Include troubleshooting guides
Code Quality
- Testing:
- Maintain high test coverage (aim for 80%+)
- Test edge cases and error conditions
- Include both unit and integration tests
- Security:
- Never log sensitive data
- Validate all inputs
- Follow principle of least privilege
- Performance:
- Optimize for speed and resource usage
- Minimize external command calls
- Cache expensive operations when possible
Plugin Architecture
- Compatibility:
- Maintain backward compatibility within major versions
- Use feature detection for optional functionality
- Document version requirements
- Logging:
- Use appropriate log levels (DEBUG, INFO, WARN, ERROR)
- Include timestamps and context in logs
- Support structured logging for machine processing
- Resource Management:
- Clean up temporary files and resources
- Handle signals and shutdown gracefully
- Implement timeouts for long-running operations
Plugin-Specific Guidelines
- Service Plugins:
- Implement full lifecycle management
- Support backup/restore operations
- Handle data persistence and migrations
- Utility Plugins:
- Focus on single responsibility
- Support dry-run mode
- Include validation for all inputs
- Core Plugins:
- Follow established patterns from official plugins
- Document all configuration options
- Include upgrade paths for existing users
Development Workflow
- Version Control:
- Use semantic versioning
- Create meaningful commit messages
- Use feature branches and pull requests
- CI/CD:
- Automate testing and releases
- Run linters and static analysis
- Generate changelogs automatically
- Community:
- Document contribution guidelines
- Include a code of conduct
- Be responsive to issues and PRs
Example Plugins
Service Plugin: dokku-postgres
- Repository: dokku/dokku-postgres
- Key Features:
- Full database lifecycle management
- Backup/restore functionality
- User and permission management
- SSL configuration
- Notable Patterns:
- Well-structured subcommands
- Comprehensive test suite
- Detailed documentation
Utility Plugin: dokku-letsencrypt
- Repository: dokku/dokku-letsencrypt
- Key Features:
- Automatic SSL certificate management
- Certificate renewal
- Nginx configuration
- Notable Patterns:
- Cron-based scheduling
- Template-based configuration
- Clean error handling
Core Plugin: dokku-redis
- Repository: dokku/dokku-redis
- Key Features:
- Redis instance management
- Data persistence
- Service linking
- Notable Patterns:
- Consistent command structure
- Integration with Dokku networking
- Clear user feedback
Plugin Development Checklist
When developing a new Dokku plugin, ensure you've covered these aspects:
Core Functionality
- Implement all required lifecycle hooks
- Support all standard commands (create, destroy, info, etc.)
- Handle errors gracefully
- Validate all inputs
User Experience
- Provide clear help text for all commands
- Include usage examples
- Document configuration options
- Support common environment variables
Testing
- Write unit tests for core functions
- Include integration tests
- Test error conditions
- Verify plugin uninstallation
Documentation
- Complete README
- Command reference
- Installation instructions
- Upgrade guides
Deployment
- CI/CD pipeline
- Version management
- Release process
- Changelog generation
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Update documentation
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.