Files
dokku-docker-compose/docs/PLUGIN_STYLEGUIDE.md

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

  1. Project Structure
  2. File Organization
  3. Code Style
  4. Testing
  5. Documentation
  6. Versioning
  7. CI/CD
  8. Common Patterns
  9. 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:

  1. 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"
      
  2. commands

    • Defines the main plugin commands
    • Maps commands to their implementations
    • Example:
      postgres:create  postgres-create
      postgres:destroy postgres-destroy
      
  3. subcommands/

    • One file per subcommand
    • Naming: plugin-command (e.g., postgres-create)
    • Each file should be executable and include help text
  4. tests/

    • BATS test files
    • Mirror the command structure
    • Include both unit and integration tests

File Organization

Core Files

  1. 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"
      
  2. Makefile

    • Standard build and test targets
    • Common targets: build, test, lint, install
    • Example:
      .PHONY: test
      test:
      	@bats tests/
      
  3. 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 bash for portability
  • Follow Google's Shell Style Guide
  • Use local for 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 pipefail at the start of scripts
  • Provide meaningful error messages
  • Use trap for 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 ronn or 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 v prefix (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

  1. Update version in plugin.toml
  2. Update CHANGELOG.md
  3. Create git tag
  4. Push tag to trigger release
  5. 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

  1. Idempotency: All commands should be idempotent (running them multiple times has the same effect as running them once)
  2. Error Handling:
    • Provide clear, actionable error messages
    • Include error codes for programmatic handling
    • Clean up resources on failure
  3. Documentation:
    • Document all commands with examples
    • Keep README and help text up-to-date
    • Include troubleshooting guides

Code Quality

  1. Testing:
    • Maintain high test coverage (aim for 80%+)
    • Test edge cases and error conditions
    • Include both unit and integration tests
  2. Security:
    • Never log sensitive data
    • Validate all inputs
    • Follow principle of least privilege
  3. Performance:
    • Optimize for speed and resource usage
    • Minimize external command calls
    • Cache expensive operations when possible

Plugin Architecture

  1. Compatibility:
    • Maintain backward compatibility within major versions
    • Use feature detection for optional functionality
    • Document version requirements
  2. Logging:
    • Use appropriate log levels (DEBUG, INFO, WARN, ERROR)
    • Include timestamps and context in logs
    • Support structured logging for machine processing
  3. Resource Management:
    • Clean up temporary files and resources
    • Handle signals and shutdown gracefully
    • Implement timeouts for long-running operations

Plugin-Specific Guidelines

  1. Service Plugins:
    • Implement full lifecycle management
    • Support backup/restore operations
    • Handle data persistence and migrations
  2. Utility Plugins:
    • Focus on single responsibility
    • Support dry-run mode
    • Include validation for all inputs
  3. Core Plugins:
    • Follow established patterns from official plugins
    • Document all configuration options
    • Include upgrade paths for existing users

Development Workflow

  1. Version Control:
    • Use semantic versioning
    • Create meaningful commit messages
    • Use feature branches and pull requests
  2. CI/CD:
    • Automate testing and releases
    • Run linters and static analysis
    • Generate changelogs automatically
  3. 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

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Update documentation
  6. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.