| title | Contributing |
|---|
Thank you for your interest in contributing! This guide covers everything you need to get started.
Be respectful and constructive. We follow the Contributor Covenant.
- macOS 26+ (for full container support) or macOS 14+ (for development with placeholders)
- Swift 6.0+
- Xcode 16+
git clone https://github.com/us/mocker.git
cd mocker
# Build in debug mode
swift build
# Run tests
swift test
# Run the CLI directly
swift run mocker --helpVS Code with the Swift extension:
code .
# Install: Swift for VS Code (sswg.swift-lang)Xcode:
open Package.swift# Remove all Mocker state (containers, images, networks, volumes)
rm -rf ~/.mocker
# Rebuild and test
swift build && swift run mocker system infoSee architecture.md for a full breakdown. Key directories:
Sources/MockerKit/ # Core library — most feature work goes here
Sources/Mocker/ # CLI commands — UI/formatting work goes here
Sources/MockerApp/ # MenuBar GUI — SwiftUI work goes here
Tests/ # Unit and integration tests
docs/ # Documentation
git checkout -b feat/my-feature
# or
git checkout -b fix/bug-descriptionFollow the patterns in existing code:
- New commands: add a file in
Sources/Mocker/Commands/ - New engine methods: add to the relevant actor in
MockerKit - New models: add to
Sources/MockerKit/Models/
Add tests for any new functionality in Tests/MockerKitTests/:
@Test("My new feature works")
func testMyFeature() throws {
// ...
}swift build
swift test
swift run mocker --help # smoke test- Use Swift 6 strict concurrency — all actors must be properly
awaited - Prefer
actorfor any stateful component - Use
async throwsfor all I/O operations - Prefer
structoverclassfor value types - Use
guardfor early returns
When implementing or modifying commands, check against Docker's output:
# Check Docker behavior
docker run --help
docker inspect <container>
# Compare with Mocker
swift run mocker run --help
swift run mocker inspect <container>Key compatibility rules:
- Error messages must match:
Error response from daemon: ... inspectalways returns a JSON array[{...}]stopandrmecho back the user's input identifier (not the resolved name)- Short IDs are exactly 12 characters
- Container/image/network/volume names: follow Docker conventions
- Swift types: PascalCase for types, camelCase for properties/methods
- CLI flags: kebab-case matching Docker (
--no-stream,--project-name)
Use Conventional Commits:
feat: add mocker login command
fix: correct container name echo in stop command
docs: update cli-reference with new flags
test: add tests for network connect/disconnect
refactor: extract image validation into helper
chore: update Yams dependency to 5.2
Maximum 72 characters for the subject line.
# All tests
swift test
# Specific suite
swift test --filter MockerKitTests
swift test --filter MockerTests
# Specific test
swift test --filter "ContainerConfigTests/testParsePortMapping"Tests/
├── MockerKitTests/
│ ├── ContainerConfigTests.swift # PortMapping, VolumeMount parsing
│ ├── ImageReferenceTests.swift # ImageReference.parse()
│ └── ComposeFileTests.swift # YAML parsing
└── MockerTests/
└── CLITests.swift # CLI smoke tests
Use the Testing framework (Swift 6):
import Testing
@testable import MockerKit
@Suite("MyFeature Tests")
struct MyFeatureTests {
@Test("Parse valid input")
func testParseValid() throws {
let result = try MyType.parse("valid-input")
#expect(result.value == "expected")
}
@Test("Parse invalid input throws")
func testParseInvalid() {
#expect(throws: MockerError.self) {
try MyType.parse("")
}
}
}For commands that affect state, use a temporary config:
let tempDir = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
let config = MockerConfig(dataRoot: tempDir.path)
try config.ensureDirectories()
// ... test with this config- Ensure tests pass:
swift test - Ensure it builds:
swift build - Self-review your diff — remove debug prints, check for typos
- Write a clear PR description:
- What problem does this solve?
- How was it tested?
- Any breaking changes?
PR title follows Conventional Commits format:
feat: add mocker login commandfix: prevent duplicate images on repeated pulldocs: add compose guide
The highest-impact contributions are replacing placeholder implementations with real Apple Containerization framework calls. Look for // TODO: comments:
grep -r "TODO:" Sources/MockerKit/Image Pull (ImageManager.swift):
// TODO: Use Containerization framework to actually pull the image
// Replace with Apple Containerization image pull APIContainer Start (ContainerEngine.swift):
// TODO: Use Containerization framework to start the container
// Replace with Container() init + start()Container Logs (ContainerEngine.swift):
// TODO: Stream real logs from the container process- Keep the existing method signature — callers should not change
- The placeholder
ContainerInforeturned should match the real framework's data - Add error handling for framework-specific errors, mapping to
MockerError - Update the relevant tests
Open an issue with the question label, or start a GitHub Discussion.