Contributing Guide¶
Thank you for considering contributing to Docker Pilot! This guide provides all the information needed to contribute effectively to the project.
Table of Contents¶
- Code of Conduct
- How to Contribute
- Environment Setup
- Project Structure
- Code Standards
- Testing
- Documentation
- Review Process
- Releases
Code of Conduct¶
This project and all participants are governed by the Code of Conduct. By participating, you agree to follow this code.
Expected Behavior¶
- Use welcoming and inclusive language
- Respect different viewpoints and experiences
- Accept constructive criticism gracefully
- Focus on what is best for the community
- Show empathy towards other community members
Unacceptable Behavior¶
- Use of sexualized language or imagery
- Trolling, insulting/derogatory comments
- Public or private harassment
- Publishing private information without permission
- Any conduct considered inappropriate in a professional environment
How to Contribute¶
There are several ways to contribute to Docker Pilot:
1. Report Bugs¶
If you found a bug, help us by creating an issue:
- Check if the bug has already been reported
- Use the bug report template
- Include detailed environment information
- Provide steps to reproduce the problem
- Add logs and screenshots when relevant
Bug Report Template:
**Bug Description**
Clear and concise description of the problem.
**Steps to Reproduce**
1. Go to '...'
2. Click on '....'
3. Execute '....'
4. See the error
**Expected Behavior**
What you expected to happen.
**Screenshots**
If applicable, add screenshots.
**Environment:**
- OS: [e.g. Windows, macOS, Linux]
- Docker Version: [e.g. 24.0.7]
- Docker Pilot Version: [e.g. 1.0.0]
- Node.js Version: [e.g. 18.17.0]
**Additional Information**
Any additional context about the problem.
2. Suggest Improvements¶
To suggest a new feature:
- Check if the feature has already been suggested
- Use the feature request template
- Clearly describe the problem it solves
- Provide usage examples
- Consider alternatives
Feature Request Template:
**Feature Description**
Clear and concise description of the desired feature.
**Problem Solved**
What problem does this feature solve?
**Proposed Solution**
How would you like it to work?
**Alternatives Considered**
What other solutions have you considered?
**Additional Context**
Any additional relevant information.
3. Contribute Code¶
To contribute code:
- Fork the repository
- Create a branch for your feature
- Make your changes
- Add tests
- Run the tests
- Commit your changes
- Create a pull request
Environment Setup¶
Prerequisites¶
- Node.js 18.x or higher
- npm 9.x or higher
- Docker 24.x or higher
- Git 2.x or higher
Installation¶
- Clone the repository:
- Install dependencies:
- Configure development environment:
# Create local configuration file
cp .env.example .env.local
# Install development tools
npm run dev:setup
- Build the project:
- Run tests:
Docker Configuration¶
Docker Pilot requires Docker to be running:
# Check if Docker is running
docker version
# Start Docker (if needed)
# Windows/macOS: Start Docker Desktop
# Linux: sudo systemctl start docker
IDE Configuration¶
Visual Studio Code¶
Install recommended extensions:
- TypeScript Hero - Import organization
- ESLint - Code linting
- Prettier - Code formatting
- Jest - Test execution
- Docker - Docker support
Recommended configuration (.vscode/settings.json
):
{
"typescript.preferences.importModuleSpecifier": "relative",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"jest.autoRun": "watch",
"files.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/.git": true
}
}
Project Structure¶
docker-pilot/
βββ src/ # Source code
β βββ core/ # Core functionality
β β βββ DockerPilot.ts
β β βββ CommandRunner.ts
β β βββ ConfigManager.ts
β β βββ ServiceManager.ts
β βββ commands/ # Command implementations
β β βββ container/
β β βββ image/
β β βββ volume/
β β βββ network/
β βββ utils/ # Utilities
β β βββ DockerUtils.ts
β β βββ FileUtils.ts
β β βββ Logger.ts
β β βββ ValidationUtils.ts
β βββ types/ # Type definitions
β β βββ index.ts
β βββ plugins/ # Plugin system
β β βββ PluginManager.ts
β β βββ types.ts
β βββ index.ts # Entry point
βββ tests/ # Tests
β βββ unit/
β βββ integration/
β βββ e2e/
β βββ fixtures/
βββ docs/ # Documentation
βββ scripts/ # Build/deploy scripts
βββ .github/ # GitHub workflows
βββ config/ # Configurations
Important Files¶
package.json
- Project configuration and dependenciestsconfig.json
- TypeScript configurationjest.config.js
- Test configuration.eslintrc.js
- ESLint configuration.prettierrc
- Prettier configurationdocker-compose.yml
- Development environment
Code Standards¶
Code Style¶
We follow TypeScript and ESLint conventions:
// β
Good
class ContainerManager {
private readonly containers: Map<string, Container> = new Map();
async startContainer(name: string): Promise<void> {
const container = this.containers.get(name);
if (!container) {
throw new Error(`Container ${name} not found`);
}
await container.start();
}
}
// β Bad
class containerManager {
private containers: any;
startContainer(name) {
return this.containers.get(name).start();
}
}
Naming Conventions¶
- Classes: PascalCase (
ContainerManager
) - Methods/Functions: camelCase (
startContainer
) - Variables: camelCase (
containerName
) - Constants: UPPER_SNAKE_CASE (
DEFAULT_TIMEOUT
) - Interfaces: PascalCase with I prefix (
IContainerConfig
) - Types: PascalCase (
ContainerStatus
) - Enums: PascalCase (
LogLevel
)
File Structure¶
// file: src/utils/ContainerUtils.ts
import { Container, ContainerStatus } from '../types';
import { DockerClient } from '../core/DockerClient';
import { Logger } from './Logger';
/**
* Utilities for managing Docker containers
*/
export class ContainerUtils {
private static readonly logger = new Logger('ContainerUtils');
/**
* Checks if a container is running
* @param container Container to check
* @returns true if running
*/
static isRunning(container: Container): boolean {
return container.status === ContainerStatus.Running;
}
/**
* Gets containers by status
* @param client Docker client
* @param status Desired status
* @returns List of containers
*/
static async getByStatus(
client: DockerClient,
status: ContainerStatus
): Promise<Container[]> {
try {
const containers = await client.listContainers();
return containers.filter(c => c.status === status);
} catch (error) {
this.logger.error('Error getting containers by status', error);
throw error;
}
}
}
Error Handling¶
// β
Good - Specific handling
async function stopContainer(name: string): Promise<void> {
try {
const container = await findContainer(name);
if (!container) {
throw new ContainerNotFoundError(`Container ${name} not found`);
}
await container.stop();
logger.info(`Container ${name} stopped successfully`);
} catch (error) {
if (error instanceof ContainerNotFoundError) {
logger.warn(`Container ${name} not found`);
} else {
logger.error(`Error stopping container ${name}`, error);
}
throw error;
}
}
// β Bad - Generic handling
async function stopContainer(name: string): Promise<void> {
try {
const container = await findContainer(name);
await container.stop();
} catch (error) {
console.log('Error:', error);
}
}
Code Documentation¶
/**
* Manages Docker container operations
*
* @example
* ```typescript
* const manager = new ContainerManager();
* await manager.start('nginx');
* ```
*/
export class ContainerManager {
/**
* Starts a container
*
* @param name Container name
* @param options Start options
* @throws {ContainerNotFoundError} When container doesn't exist
* @throws {ContainerAlreadyRunningError} When container is already running
* @returns Promise that resolves when container starts
*/
async start(name: string, options?: StartOptions): Promise<void> {
// implementation
}
}
Testing¶
Test Structure¶
tests/
βββ unit/ # Unit tests
β βββ core/
β βββ utils/
β βββ commands/
βββ integration/ # Integration tests
β βββ docker/
β βββ api/
βββ e2e/ # End-to-end tests
β βββ cli/
β βββ scenarios/
βββ fixtures/ # Test data
β βββ containers/
β βββ images/
β βββ configs/
βββ helpers/ # Test utilities
βββ setup.ts
βββ teardown.ts
βββ mocks.ts
Test Patterns¶
Unit Tests¶
// file: tests/unit/utils/ContainerUtils.test.ts
import { ContainerUtils } from '../../../src/utils/ContainerUtils';
import { Container, ContainerStatus } from '../../../src/types';
import { createMockContainer } from '../../helpers/mocks';
describe('ContainerUtils', () => {
describe('isRunning', () => {
it('should return true for running container', () => {
// Arrange
const container = createMockContainer({
status: ContainerStatus.Running
});
// Act
const result = ContainerUtils.isRunning(container);
// Assert
expect(result).toBe(true);
});
it('should return false for stopped container', () => {
// Arrange
const container = createMockContainer({
status: ContainerStatus.Exited
});
// Act
const result = ContainerUtils.isRunning(container);
// Assert
expect(result).toBe(false);
});
});
describe('getByStatus', () => {
it('should filter containers by status', async () => {
// Arrange
const mockClient = {
listContainers: jest.fn().mockResolvedValue([
createMockContainer({ status: ContainerStatus.Running }),
createMockContainer({ status: ContainerStatus.Exited }),
createMockContainer({ status: ContainerStatus.Running })
])
};
// Act
const result = await ContainerUtils.getByStatus(
mockClient as any,
ContainerStatus.Running
);
// Assert
expect(result).toHaveLength(2);
expect(result.every(c => c.status === ContainerStatus.Running)).toBe(true);
});
});
});
Integration Tests¶
// file: tests/integration/docker/ContainerManager.test.ts
import { ContainerManager } from '../../../src/core/ContainerManager';
import { DockerClient } from '../../../src/core/DockerClient';
import { setupTestEnvironment, teardownTestEnvironment } from '../../helpers/setup';
describe('ContainerManager Integration', () => {
let containerManager: ContainerManager;
let dockerClient: DockerClient;
beforeAll(async () => {
await setupTestEnvironment();
dockerClient = new DockerClient();
containerManager = new ContainerManager(dockerClient);
});
afterAll(async () => {
await teardownTestEnvironment();
});
beforeEach(async () => {
// Clean test containers
await dockerClient.pruneContainers();
});
it('should create and start container', async () => {
// Arrange
const containerName = 'test-nginx';
const image = 'nginx:alpine';
// Act
await containerManager.create(containerName, image);
await containerManager.start(containerName);
// Assert
const container = await dockerClient.getContainer(containerName);
expect(container.status).toBe('running');
});
});
E2E Tests¶
// file: tests/e2e/cli/container-commands.test.ts
import { execSync } from 'child_process';
import { setupTestEnvironment } from '../../helpers/setup';
describe('Container Commands E2E', () => {
beforeAll(async () => {
await setupTestEnvironment();
});
it('should list containers via CLI', () => {
// Act
const output = execSync('docker-pilot list containers', {
encoding: 'utf8'
});
// Assert
expect(output).toContain('CONTAINER ID');
expect(output).toContain('IMAGE');
expect(output).toContain('STATUS');
});
it('should start container via CLI', () => {
// Arrange
execSync('docker run -d --name test-nginx nginx:alpine');
// Act
const output = execSync('docker-pilot start test-nginx', {
encoding: 'utf8'
});
// Assert
expect(output).toContain('Container test-nginx started');
});
});
Running Tests¶
# All tests
npm test
# Unit tests
npm run test:unit
# Integration tests
npm run test:integration
# E2E tests
npm run test:e2e
# Tests with coverage
npm run test:coverage
# Tests in watch mode
npm run test:watch
# Specific tests
npm test -- --testNamePattern="ContainerUtils"
npm test -- --testPathPattern="container"
Mocks and Fixtures¶
// file: tests/helpers/mocks.ts
import { Container, ContainerStatus } from '../../src/types';
export function createMockContainer(overrides: Partial<Container> = {}): Container {
return {
id: 'mock-container-id',
name: 'mock-container',
image: 'nginx:latest',
status: ContainerStatus.Running,
created: new Date(),
ports: [],
volumes: [],
networks: [],
...overrides
};
}
export function createMockDockerClient() {
return {
listContainers: jest.fn(),
getContainer: jest.fn(),
createContainer: jest.fn(),
startContainer: jest.fn(),
stopContainer: jest.fn(),
removeContainer: jest.fn()
};
}
Documentation¶
Code Documentation¶
- Use JSDoc to document public classes, methods, and functions
- Include usage examples when appropriate
- Document parameters, returns, and exceptions
- Use
@deprecated
for obsolete features
API Documentation¶
- Keep API documentation up to date
- Use practical examples
- Document all endpoints and parameters
- Include response codes and examples
README and Guides¶
- Keep README.md updated
- Include installation and usage guides
- Add common troubleshooting
- Document important changes
Review Process¶
Pull Request Checklist¶
Before creating a PR, check:
- Code follows established standards
- Tests were added/updated
- Documentation was updated
- Builds pass without errors
- No merge conflicts
- Commit messages are descriptive
Pull Request Template¶
## Description
Brief description of the changes made.
## Type of Change
- [ ] Bug fix (change that fixes an issue)
- [ ] New feature (change that adds functionality)
- [ ] Breaking change (change that breaks compatibility)
- [ ] Documentation (documentation changes only)
## How It Was Tested
Describe the tests performed to verify the changes.
## Checklist
- [ ] My code follows the project standards
- [ ] I performed a self-review of the code
- [ ] I commented complex code
- [ ] I updated documentation
- [ ] Tests pass locally
- [ ] I added tests that prove the fix/feature works
## Screenshots (if applicable)
Add screenshots for UI changes.
Processo de Review¶
- Automated Checks: CI/CD executa testes e linting
- Code Review: Pelo menos um maintainer deve aprovar
- Manual Testing: Testes manuais se necessΓ‘rio
- Merge: Squash and merge para manter histΓ³rico limpo
Releases¶
Versioning¶
We follow Semantic Versioning:
- MAJOR: Changes that break compatibility
- MINOR: New compatible features
- PATCH: Compatible bug fixes
Release Process¶
- Preparation:
- Update CHANGELOG.md
- Bump version in package.json
-
Update documentation
-
Testing:
- Run all tests
- Integration tests
-
Manual testing
-
Release:
- Create version tag
- Publish to npm
- Create GitHub release
-
Update documentation
-
Post-Release:
- Verify deployment
- Monitor issues
- Communicate to community
Changelog¶
We maintain a detailed changelog following Keep a Changelog:
# Changelog
## [1.2.0] - 2024-01-15
### Added
- New container monitoring feature
- Support for Docker Compose v2
- Command for automatic resource cleanup
### Changed
- Improved container listing performance
- Updated interactive menu interface
### Fixed
- Fixed bug in container name validation
- Resolved port conflict issue
### Deprecated
- Command `docker-pilot old-command` will be removed in v2.0
### Removed
- Removed support for Docker Engine < 20.10
### Security
- Fixed vulnerability in input validation
Development Tools¶
NPM Scripts¶
{
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"lint": "eslint src tests --ext .ts",
"lint:fix": "eslint src tests --ext .ts --fix",
"format": "prettier --write src tests",
"format:check": "prettier --check src tests",
"dev": "ts-node src/index.ts",
"dev:debug": "ts-node --inspect src/index.ts",
"clean": "rm -rf dist coverage",
"precommit": "npm run lint && npm run test",
"prepush": "npm run build && npm run test:coverage"
}
}
Git Hooks¶
# .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run precommit
# .husky/pre-push
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run prepush
CI/CD Configuration¶
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${ { matrix.node-version } }
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm run test:coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
Additional Resources¶
Useful Links¶
Community¶
- GitHub Issues: For bugs and feature requests
- Discussions: For general discussions
- Discord: For real-time chat
- Stack Overflow: For technical questions (tag: docker-pilot)
Mentorship¶
New contributors are welcome! If you're new to the project:
- Start with issues marked as "good first issue"
- Read all documentation
- Ask questions in discussions
- Participate in community meetings
- Ask for help when needed
Recognition¶
All contributors are recognized in the CONTRIBUTORS.md file and the project credits page. Contributions include:
- Code
- Documentation
- Tests
- Reviews
- Bug reports
- Feature suggestions
- Translation
- Design
- Community support
Thank you for contributing to Docker Pilot! π