Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/tests export-ignore
/vendor export-ignore

/LICENSE export-ignore
/Makefile export-ignore
/README.md export-ignore
/phpmd.xml export-ignore
/phpunit.xml export-ignore
/phpstan.neon.dist export-ignore
/infection.json.dist export-ignore

/.github export-ignore
/.gitignore export-ignore
/.gitattributes export-ignore
22 changes: 22 additions & 0 deletions .github/workflows/auto-assign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Auto assign issues

on:
issues:
types:
- opened

jobs:
run:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Assign issues
uses: gustavofreze/auto-assign@1.0.0
with:
assignees: '${{ secrets.ASSIGNEES }}'
github_token: '${{ secrets.GITHUB_TOKEN }}'
allow_self_assign: 'true'
allow_no_assignees: 'true'
assignment_options: 'ISSUE'
62 changes: 62 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: CI

on:
push:
pull_request:

env:
PHP_VERSION: '8.3'

jobs:
auto-review:
name: Auto review
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configure PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ env.PHP_VERSION }}

- name: Install dependencies
run: composer update --no-progress --optimize-autoloader

- name: Run review
run: composer review

tests:
name: Tests
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configure PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ env.PHP_VERSION }}

- name: Install dependencies
run: composer update --no-progress --optimize-autoloader

- name: Clean up Docker
run: docker system prune -f

- name: Create Docker network
run: docker network create tiny-blocks

- name: Create Docker volume for migrations
run: docker volume create migrations

- name: Run tests
run: |
docker run --network=tiny-blocks \
-v ${PWD}:/app \
-v ${PWD}/tests/Integration/Database/Migrations:/migrations \
-v /var/run/docker.sock:/var/run/docker.sock \
-w /app \
gustavofreze/php:${{ env.PHP_VERSION }} bash -c "composer tests"
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.idea

/vendor/
/report
*.lock
.phpunit.*
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
DOCKER_RUN = docker run -u root --rm -it --network=tiny-blocks --name test-lib -v ${PWD}:/app -v ${PWD}/tests/Integration/Database/Migrations:/migrations -v /var/run/docker.sock:/var/run/docker.sock -w /app gustavofreze/php:8.3

.PHONY: configure test unit-test test-no-coverage create-volume create-network review show-reports clean

configure:
@${DOCKER_RUN} composer update --optimize-autoloader

test: create-volume
@${DOCKER_RUN} composer tests

unit-test:
@${DOCKER_RUN} composer run unit-test

test-no-coverage: create-volume
@${DOCKER_RUN} composer tests-no-coverage

create-network:
@docker network create tiny-blocks

create-volume:
@docker volume create migrations

review:
@${DOCKER_RUN} composer review

show-reports:
@sensible-browser report/coverage/coverage-html/index.html

clean:
@sudo chown -R ${USER}:${USER} ${PWD}
@rm -rf report vendor .phpunit.cache
235 changes: 233 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,233 @@
# docker-container
Manage Docker containers programmatically, simplifying the creation, running, and interaction with containers.
# Docker container

[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)

* [Overview](#overview)
* [Installation](#installation)
* [How to use](#how-to-use)
* [Creating a container](#creating-a-container)
* [Running a container](#running-a-container)
* [Running a container if it doesn't exist](#running-a-container-if-it-doesnt-exist)
* [Setting network](#setting-network)
* [Setting port mappings](#setting-port-mappings)
* [Setting volumes mappings](#setting-volumes-mappings)
* [Setting environment variables](#setting-environment-variables)
* [Disabling auto-remove](#disabling-auto-remove)
* [Copying files to a container](#copying-files-to-a-container)
* [Waiting for a condition](#waiting-for-a-condition)
* [Usage examples](#usage-examples)
* [License](#license)
* [Contributing](#contributing)

<div id='overview'></div>

## Overview

The `DockerContainer` library provides an interface and implementations to manage Docker containers programmatically.
It simplifies the creation, execution, and interaction with containers, such as adding network configurations, mapping
ports, setting environment variables, and executing commands inside containers.
Designed specifically to support **unit tests** and **integration tests**, the library enables developers to simulate
and manage containerized environments with minimal effort, ensuring a seamless testing workflow.

<div id='installation'></div>

## Installation

```bash
composer require tiny-blocks/docker-container
```

<div id='how-to-use'></div>

## How to use

### Creating a container

Creates a container from a specified image and optionally a name.
The `from` method can be used to initialize a new container instance with an image and an optional name for
identification.

```php
$container = GenericDockerContainer::from(image: 'php:8.3-fpm', name: 'my-container');
```

### Running a container

The `run` method starts a container.
Optionally, it allows you to execute commands within the container after it has started and define a condition to wait
for using a `ContainerWaitAfterStarted` instance.

**Example with no commands or conditions:**

```php
$container->run();
```

**Example with commands only:**

```php
$container->run(commands: ['ls', '-la']);
```

**Example with commands and a wait condition:**

```php
$container->run(commands: ['ls', '-la'], waitAfterStarted: ContainerWaitForTime::forSeconds(seconds: 5));
```

### Running a container if it doesn't exist

The `runIfNotExists` method starts a container only if it doesn't already exist.
Optionally, it allows you to execute commands within the container after it has started and define a condition to wait
for using a `ContainerWaitAfterStarted` instance.

```php
$container->runIfNotExists();
```

**Example with commands only:**

```php
$container->runIfNotExists(commands: ['ls', '-la']);
```

**Example with commands and a wait condition:**

```php
$container->runIfNotExists(commands: ['ls', '-la'], waitAfterStarted: ContainerWaitForTime::forSeconds(seconds: 5));
```

### Setting network

The `withNetwork` method connects the container to a specified Docker network by name, allowing you to define the
network configuration the container will use.

```php
$container->withNetwork(name: 'my-network');
```

### Setting port mappings

Maps ports between the host and the container.
The `withPortMapping` method maps a port from the host to a port inside the container.

```php
$container->withPortMapping(portOnHost: 9000, portOnContainer: 9000);
```

### Setting volumes mappings

Maps a volume from the host to the container.
The `withVolumeMapping` method allows you to link a directory from the host to the container.

```php
$container->withVolumeMapping(pathOnHost: '/path/on/host', pathOnContainer: '/path/in/container');
```

### Setting environment variables

Sets environment variables inside the container.
The `withEnvironmentVariable` method allows you to configure environment variables within the container.

```php
$container->withEnvironmentVariable(key: 'XPTO', value: '123');
```

### Disabling auto-remove

Prevents the container from being automatically removed when stopped.
By default, Docker removes containers after they stop.
The `withoutAutoRemove` method disables this feature, keeping the container around even after it finishes its
execution.

```php
$container->withoutAutoRemove();
```

### Copying files to a container

Copies files or directories from the host machine to the container.
The `copyToContainer` method allows you to transfer files from the host system into the container’s file system.

```php
$container->copyToContainer(pathOnHost: '/path/to/files', pathOnContainer: '/path/in/container');
```

### Waiting for a condition

The `withWaitBeforeRun` method allows the container to pause its execution until a specified condition is met before
starting.

```php
$container->withWaitBeforeRun(wait: ContainerWaitForDependency::untilReady(condition: MySQLReady::from(container: $container)));
```

<div id='usage-examples'></div>

## Usage examples

### MySQL and Generic Containers

The MySQL container is configured and started:

```php
$mySQLContainer = MySQLDockerContainer::from(image: 'mysql:8.1', name: 'test-database')
->withNetwork(name: 'tiny-blocks')
->withTimezone(timezone: 'America/Sao_Paulo')
->withUsername(user: 'xpto')
->withPassword(password: '123')
->withDatabase(database: 'test_adm')
->withPortMapping(portOnHost: 3306, portOnContainer: 3306)
->withRootPassword(rootPassword: 'root')
->withVolumeMapping(pathOnHost: '/var/lib/mysql', pathOnContainer: '/var/lib/mysql')
->withoutAutoRemove()
->runIfNotExists();
```

With the MySQL container started, it is possible to retrieve data, such as the address and JDBC connection URL:

```php
$jdbcUrl = $mySQLContainer->getJdbcUrl(options: 'useUnicode=yes&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false');
$database = $environmentVariables->getValueBy(key: 'MYSQL_DATABASE');
$username = $environmentVariables->getValueBy(key: 'MYSQL_USER');
$password = $environmentVariables->getValueBy(key: 'MYSQL_PASSWORD');
```

The Flyway container is configured and only starts and executes migrations after the MySQL container is **ready**:

```php
$flywayContainer = GenericDockerContainer::from(image: 'flyway/flyway:11.0.0')
->withNetwork(name: 'tiny-blocks')
->copyToContainer(pathOnHost: '/migrations', pathOnContainer: '/flyway/sql')
->withVolumeMapping(pathOnHost: '/migrations', pathOnContainer: '/flyway/sql')
->withWaitBeforeRun(
wait: ContainerWaitForDependency::untilReady(
condition: MySQLReady::from(
container: $mySQLContainer
)
)
)
->withEnvironmentVariable(key: 'FLYWAY_URL', value: $jdbcUrl)
->withEnvironmentVariable(key: 'FLYWAY_USER', value: $username)
->withEnvironmentVariable(key: 'FLYWAY_TABLE', value: 'schema_history')
->withEnvironmentVariable(key: 'FLYWAY_SCHEMAS', value: $database)
->withEnvironmentVariable(key: 'FLYWAY_EDITION', value: 'community')
->withEnvironmentVariable(key: 'FLYWAY_PASSWORD', value: $password)
->withEnvironmentVariable(key: 'FLYWAY_LOCATIONS', value: 'filesystem:/flyway/sql')
->withEnvironmentVariable(key: 'FLYWAY_CLEAN_DISABLED', value: 'false')
->withEnvironmentVariable(key: 'FLYWAY_VALIDATE_MIGRATION_NAMING', value: 'true')
->run(commands: ['-connectRetries=15', 'clean', 'migrate']);
```

<div id='license'></div>

## License

Docker container is licensed under [MIT](LICENSE).

<div id='contributing'></div>

## Contributing

Please follow the [contributing guidelines](https://github.com/tiny-blocks/tiny-blocks/blob/main/CONTRIBUTING.md) to
contribute to the project.
Loading