Thank you for your interest in contributing to Testcontainers Crystal! This document provides guidelines and instructions for contributing.
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/testcontainers-crystal.git cd testcontainers-crystal - Install dependencies:
shards install
- Run the tests:
crystal spec
- Crystal >= 1.10.0
- Docker or Docker Desktop running (for integration tests)
- Git
src/testcontainers/ # Library source code
docker_container.cr # Core container class
docker_client.cr # Docker client wrapper
network.cr # Network management
errors.cr # Exception hierarchy
containers/ # Pre-configured modules
spec/ # Test files
docker_container_spec.cr # Core container unit tests
containers_spec.cr # Preset container unit tests
network_spec.cr # Network unit tests
integration_spec.cr # Integration tests (Docker required)
- Indentation: 2 spaces (Crystal standard)
- Line length: ~120 characters
- Naming:
PascalCasefor types,snake_casefor methods/variables/files - Documentation: Add
#doc comments to all public methods and classes - Method chaining: Builder methods should return
selfto enable chaining - Error handling: Use custom exception classes from
errors.cr; avoid barerescue
- Prefer
property/gettermacros over manual getter/setter methods - Use
begin/ensurefor resource cleanup - Use blocks (
yield) for scoped resource management (seeNetwork.create) - Prefer string interpolation over concatenation
- Use
nil-safe navigation (try) where appropriate
- Create
src/testcontainers/containers/myservice.cr - Follow the pattern in
postgres.cr:- Set default image, port, and environment variables
- Add a wait strategy
- Expose a
connection_urlmethod
- Require the new file in
src/testcontainers.cr - Add unit tests in
spec/containers_spec.cr
module Testcontainers
class MyServiceContainer < DockerContainer
IMAGE = "myservice"
PORT = 9000
def initialize(image = "#{IMAGE}:latest")
super(image)
with_exposed_port(PORT)
with_env("MYSERVICE_SETTING", "value")
with_wait_for(:logs, message: /ready/)
end
def connection_url : String
port = mapped_port(PORT)
host = self.host
"myservice://#{host}:#{port}"
end
end
end- Add a
wait_for_*method insrc/testcontainers/docker_container.cr - Follow the existing timeout + retry loop pattern
- Add tests in
spec/docker_container_spec.cr
crystal spec # Unit tests (no Docker required)
crystal spec -Dintegration # Integration tests (Docker required)- Write tests for all new features
- Unit tests should not require Docker — mock or test configuration only
- Integration tests should be gated behind
-Dintegration - Clean up containers/networks in tests using
ensureblocks - Tests should be deterministic and not flaky
- Test both success paths and error cases
- Create a feature branch from
main:git checkout -b feature/my-feature
- Make your changes with clear, focused commits
- Ensure all tests pass:
crystal spec - Push and open a pull request
- Keep PRs focused on a single feature or fix
- Include tests for new functionality
- Update documentation if adding public API
- Reference any related issues
- Use clear and descriptive commit messages
- Use the present tense ("Add feature" not "Added feature")
- Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
- Limit the first line to 72 characters or less
- Reference issues and pull requests after the first line
- Use GitHub Issues for bug reports and feature requests
- Include Crystal version, Docker version, and OS
- Provide a minimal reproduction case for bugs
- Check existing issues before creating a new one
By contributing, you agree that your contributions will be licensed under the MIT License.
Feel free to reach out:
- Open an issue on GitHub
- Start a discussion in GitHub Discussions
Thank you for contributing!