Skip to content
Draft
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
82 changes: 51 additions & 31 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
# list of Docker images to use as base name for tags
images: |
Expand All @@ -32,26 +32,26 @@ jobs:
org.opencontainers.image.description=MailHog mail testing, configured for use with the pygmy stack
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
-
name: Login to DockerHub
uses: docker/login-action@v3
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GHCR
uses: docker/login-action@v3
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v6
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: .
platforms: linux/amd64,linux/arm64
Expand All @@ -61,10 +61,10 @@ jobs:

test:
needs: docker
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
-
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# Establish some SSH keys.
-
name: Setup SSH
Expand All @@ -77,33 +77,53 @@ jobs:
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
# list of Docker images to use as base name for tags
images: |
ghcr.io/${{ github.repository_owner }}/mailhog
flavor: |
latest=false
-
name: Set single image tag
id: single_tag
run: |
echo "tag=$(echo '${{ steps.meta.outputs.tags }}' | head -n1)" >> "$GITHUB_OUTPUT"
-
name: Find and Replace
uses: jacobtomlinson/gha-find-replace@v3
with:
find: "ghcr.io/pygmystack/mailhog:main"
replace: ${{ steps.meta.outputs.tags }}
include: "examples/**"
-
name: Show changes
env:
IMAGE_TAG: ${{ steps.single_tag.outputs.tag }}
run: |
grep -n ghcr examples/*
find examples/ -type f -exec sed -i.bak "s|ghcr.io/pygmystack/mailhog:main|${IMAGE_TAG}|g" {} \;
find examples/ -name "*.bak" -delete
grep -Fn ghcr examples/*
-
name: Install pygmy and dockerize via brew
name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@ebe7cd12aeb3c69ccf1a6ba5a4eba5bfdfb00b3b # main
-
name: Install homebrew packages
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_ENV_HINTS: 1
run: |
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)";
brew tap pygmystack/pygmy;
brew install pygmy;
brew install bats-core;
brew install dockerize;
echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH;
brew install pygmystack/pygmy/pygmy;
pygmy version;
-
name: Pull image for tests
run: |
docker pull ${{ steps.single_tag.outputs.tag }}
docker pull uselagoon/php-8.5-fpm
-
name: Run BATS tests
env:
IMAGE_NAME: ${{ steps.single_tag.outputs.tag }}
PHP_FPM_IMAGE: uselagoon/php-8.5-fpm
run: |
bats --tap tests/image_structure.bats
bats --tap tests/runtime.bats
-
name: Switch pygmy configs from vanilla to basic
run: |
Expand All @@ -123,7 +143,7 @@ jobs:
pygmy --config examples/pygmy.basic.yml export -o ./exported-config.yml
cat ./exported-config.yml
echo "Checking image references in started containers...";
docker container inspect amazeeio-mailhog | jq '.[].Config.Image' | grep '${{ steps.meta.outputs.tags }}';
docker container inspect amazeeio-mailhog | jq '.[].Config.Image' | grep -F '${{ steps.single_tag.outputs.tag }}';
-
name: Resolv file test
run: |
Expand All @@ -136,9 +156,9 @@ jobs:
curl http://docker.amazee.io/stats | grep 'class=px' | grep 'mailhog.docker.amazee.io';
curl http://docker.amazee.io/stats | grep 'HAProxy version';
-
name: mailhog test
name: mailpit test
run: |
curl http://mailhog.docker.amazee.io | grep 'mailhog/MailHog';
curl http://mailhog.docker.amazee.io | grep 'Mailpit';
-
name: dnsmasq version
run: |
Expand Down Expand Up @@ -185,7 +205,7 @@ jobs:
pygmy --config examples/pygmy.yml export -o ./exported-config-2.yml
cat ./exported-config-2.yml
echo "Checking image references in started containers...";
docker container inspect amazeeio-mailhog | jq '.[].Config.Image' | grep '${{ steps.meta.outputs.tags }}';
docker container inspect amazeeio-mailhog | jq '.[].Config.Image' | grep -F '${{ steps.single_tag.outputs.tag }}';
-
name: SSH Key test
run: |
Expand All @@ -201,14 +221,14 @@ jobs:
name: "[Example] Drupal Base"
run: |
cd lagoon-examples/drupal-base;
docker-compose -p drupal-base up -d;
docker-compose -p drupal-base exec -T cli composer install;
docker compose -p drupal-base up -d;
docker compose -p drupal-base exec -T cli composer install;
dockerize -wait http://drupal-base.docker.amazee.io:80 -timeout 10s;
curl --HEAD http://drupal-base.docker.amazee.io;
curl --HEAD http://drupal-base.docker.amazee.io | grep -i "x-lagoon";
pygmy --config examples/pygmy.yml status | grep '\- http://drupal-base.docker.amazee.io';
docker-compose -p drupal-base down;
docker-compose -p drupal-base rm;
docker compose -p drupal-base down;
docker compose -p drupal-base rm;
cd ../../;
-
name: Test the stop command
Expand Down
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"chat.tools.terminal.autoApprove": {
"bats": true
}
}
15 changes: 5 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
FROM golang:1.21-alpine3.19 as builder
FROM axllent/mailpit:v1.29

RUN apk --no-cache add --virtual \
build-dependencies \
git \
&& GOPATH=/tmp/gocode go install github.com/mailhog/MailHog@v1.0.1
ENV MP_UI_BIND_ADDR=[::]:80

FROM alpine:3.19
WORKDIR /bin
COPY --from=builder tmp/gocode/bin/MailHog /bin/MailHog
EXPOSE 1025 8025
ENTRYPOINT ["MailHog"]
RUN ln -s /mailpit /bin/MailHog

ENTRYPOINT ["/mailpit"]
52 changes: 52 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
PHP_FPM_IMAGE ?= uselagoon/php-8.5-fpm
IMAGE_NAME ?= pygmystack/mailhog
IMAGE_TAG ?= test
FULL_IMAGE := $(IMAGE_NAME):$(IMAGE_TAG)

.DEFAULT_GOAL := help

.PHONY: help build test test-bats test-structure test-runtime shell clean

help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}'

build: ## Build the Docker image
docker build --tag $(FULL_IMAGE) .

test: build ## Build the image and run all BATS tests (requires: brew install bats-core)
@command -v bats >/dev/null 2>&1 || { \
echo "Error: bats is not installed. Install with: brew install bats-core"; \
exit 1; \
}
docker pull $(PHP_FPM_IMAGE)
IMAGE_NAME=$(FULL_IMAGE) PHP_FPM_IMAGE=$(PHP_FPM_IMAGE) bats --tap tests/

test-bats: ## Run all BATS tests without rebuilding the image
@command -v bats >/dev/null 2>&1 || { \
echo "Error: bats is not installed. Install with: brew install bats-core"; \
exit 1; \
}
docker pull $(PHP_FPM_IMAGE)
IMAGE_NAME=$(FULL_IMAGE) PHP_FPM_IMAGE=$(PHP_FPM_IMAGE) bats --tap tests/

test-structure: ## Run image structure tests only (no running container required)
@command -v bats >/dev/null 2>&1 || { \
echo "Error: bats is not installed. Install with: brew install bats-core"; \
exit 1; \
}
IMAGE_NAME=$(FULL_IMAGE) bats --tap tests/image_structure.bats

test-runtime: ## Run runtime and email-flow tests (starts a MailHog container)
@command -v bats >/dev/null 2>&1 || { \
echo "Error: bats is not installed. Install with: brew install bats-core"; \
exit 1; \
}
docker pull $(PHP_FPM_IMAGE)
IMAGE_NAME=$(FULL_IMAGE) PHP_FPM_IMAGE=$(PHP_FPM_IMAGE) bats --tap tests/runtime.bats

shell: ## Open an interactive shell inside the container
docker run --rm -it --entrypoint sh $(FULL_IMAGE)

clean: ## Remove the local test Docker image
docker rmi $(FULL_IMAGE) 2>/dev/null || true
63 changes: 63 additions & 0 deletions tests/image_structure.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env bats
# Image structure tests — verify the binary, exposed ports, entrypoint, and
# working directory baked into the Mailpit image. Tests run ephemeral
# containers and do not require a long-running process.

bats_require_minimum_version 1.5.0

IMAGE="${IMAGE_NAME:-pygmystack/mailhog:test}"

# ---------------------------------------------------------------------------
# Binary
# ---------------------------------------------------------------------------

@test "mailpit binary is present at /mailpit" {
run docker run --rm --entrypoint sh "${IMAGE}" -c 'test -f /mailpit'
[ "$status" -eq 0 ]
}

@test "mailpit binary is executable" {
run docker run --rm --entrypoint sh "${IMAGE}" -c 'test -x /mailpit'
[ "$status" -eq 0 ]
}

@test "/bin/MailHog symlink points to /mailpit" {
run docker run --rm --entrypoint sh "${IMAGE}" -c 'test -L /bin/MailHog'
[ "$status" -eq 0 ]
}

# ---------------------------------------------------------------------------
# Exposed ports (image metadata)
# ---------------------------------------------------------------------------

@test "image declares SMTP port 1025 as exposed" {
run docker inspect --format='{{json .Config.ExposedPorts}}' "${IMAGE}"
[ "$status" -eq 0 ]
[[ "$output" =~ "1025" ]]
}

@test "image declares HTTP port 80 as exposed" {
run docker inspect --format='{{json .Config.ExposedPorts}}' "${IMAGE}"
[ "$status" -eq 0 ]
[[ "$output" =~ "\"80" ]]
}

# ---------------------------------------------------------------------------
# Entrypoint
# ---------------------------------------------------------------------------

@test "image entrypoint is mailpit" {
run docker inspect --format='{{json .Config.Entrypoint}}' "${IMAGE}"
[ "$status" -eq 0 ]
[[ "$output" =~ "mailpit" ]]
}

# ---------------------------------------------------------------------------
# Working directory
# ---------------------------------------------------------------------------

@test "image working directory is /" {
run docker inspect --format='{{.Config.WorkingDir}}' "${IMAGE}"
[ "$status" -eq 0 ]
[ "$output" = "/" ]
}
Loading
Loading