From 4f45e4c9a6d1dda764818ec52bcba23e26d63bc9 Mon Sep 17 00:00:00 2001 From: Hein Date: Fri, 18 Sep 2026 20:17:24 +0200 Subject: [PATCH] feat(ci): add Docker image build and release workflow * Implement GitHub Actions workflow for Docker image build and release * Validate release tags and manage Docker login credentials * Build and push Docker images with versioning and metadata * Add docker-build target to Makefile for local image building --- .github/workflows/docker-release.yml | 74 ++++++++++++++++++++++++++++ Makefile | 35 +++++++++---- pkg/broker/config/config.go | 2 +- pkg/broker/install/install.go | 2 +- pkg/broker/queue/queue.go | 20 ++++---- pkg/broker/worker/worker.go | 2 +- 6 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/docker-release.yml diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml new file mode 100644 index 0000000..ee05a81 --- /dev/null +++ b/.github/workflows/docker-release.yml @@ -0,0 +1,74 @@ +name: Build & Release Docker Image + +on: + push: + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + tag: + description: 'Existing tag to release (e.g. v0.1.0)' + required: true + type: string + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + env: + IMAGE: git.warky.dev/wdevs/pgsql-broker + TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} + steps: + - name: Validate release tag + run: | + case "$TAG" in + v*) ;; + *) echo "Release tags must start with v (received: $TAG)" >&2; exit 1 ;; + esac + + - uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} + + - uses: docker/setup-buildx-action@v3 + + - name: Verify package registry credentials + env: + PACKAGE_REGISTRY_USERNAME: ${{ secrets.PACKAGE_REGISTRY_USERNAME }} + PACKAGE_REGISTRY_TOKEN: ${{ secrets.PACKAGE_REGISTRY_TOKEN }} + run: | + test -n "$PACKAGE_REGISTRY_USERNAME" || { + echo 'PACKAGE_REGISTRY_USERNAME is required to publish the Docker image.' >&2 + exit 1 + } + test -n "$PACKAGE_REGISTRY_TOKEN" || { + echo 'PACKAGE_REGISTRY_TOKEN is required to publish the Docker image.' >&2 + exit 1 + } + + - name: Log in to the Warky container registry + uses: docker/login-action@v3 + with: + registry: git.warky.dev + username: ${{ secrets.PACKAGE_REGISTRY_USERNAME }} + password: ${{ secrets.PACKAGE_REGISTRY_TOKEN }} + + - name: Build and push image + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile + push: true + build-args: | + VERSION=${{ env.TAG }} + COMMIT=${{ github.sha }} + BUILD_TIME=${{ github.event.head_commit.timestamp || github.event.repository.updated_at }} + tags: | + ${{ env.IMAGE }}:${{ env.TAG }} + ${{ env.IMAGE }}:latest + labels: | + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.version=${{ env.TAG }} diff --git a/Makefile b/Makefile index 2f89dbd..0bee78c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all build clean test test-all test-integration-go test-unit-go test-connection schema-install broker-start broker-stop install deps docker-up docker-down help +.PHONY: all build clean test test-all test-integration-go test-unit-go test-connection schema-install broker-start broker-stop install deps docker-up docker-down docker-build release help # Build variables BINARY_NAME=pgsql-broker @@ -32,7 +32,7 @@ COMPOSE_CMD := $(shell \ # Version information VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") -BUILD_TIME=$(shell date -u '+2026-01-02_19:58:30') +BUILD_TIME=$(shell date -u '+%Y-%m-%d_%H:%M:%S') COMMIT=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") # Inject version info @@ -73,14 +73,22 @@ schema-install: build ## Install database schema using the broker CLI @echo "Installing database schema..." @$(BIN_DIR)/$(BINARY_NAME) install --config broker.test.yaml -test-setup: build ## Start test environment (docker-compose) - @echo "Starting test environment..." - @podman-compose -f tests/docker-compose.yml up -d +test-setup: build ## Start test environment (docker-compose/podman-compose) + @echo "Starting test environment (using $(COMPOSE_CMD))..." + @if [ "$(CONTAINER_RUNTIME)" = "none" ]; then \ + echo "Error: Neither Docker nor Podman is installed"; \ + exit 1; \ + fi + @$(COMPOSE_CMD) -f tests/docker-compose.yml up -d -test-teardown: ## Stop test environment (docker-compose) - @echo "Stopping test environment..." - @podman-compose -f tests/docker-compose.yml down -v --rmi all - @sleep 5 # Give Docker time to release resources +test-teardown: ## Stop test environment (docker-compose/podman-compose) + @echo "Stopping test environment (using $(COMPOSE_CMD))..." + @if [ "$(CONTAINER_RUNTIME)" = "none" ]; then \ + echo "Neither Docker nor Podman is installed, skipping teardown"; \ + else \ + $(COMPOSE_CMD) -f tests/docker-compose.yml down -v --rmi all || true; \ + fi + @sleep 5 # Give the container runtime time to release resources broker-start: build ## Start the broker in the background @echo "Starting broker..." @@ -172,6 +180,15 @@ docker-down: ## Stop PostgreSQL test database fi @echo "PostgreSQL stopped" +docker-build: ## Build the pgsql-broker runtime image + @if [ "$(CONTAINER_RUNTIME)" = "none" ]; then echo "Error: Neither Docker nor Podman is installed"; exit 1; fi + @$(CONTAINER_RUNTIME) build \ + --build-arg VERSION=$(VERSION) \ + --build-arg COMMIT=$(COMMIT) \ + --build-arg BUILD_TIME=$(BUILD_TIME) \ + -t pgsql-broker:$(VERSION) -t pgsql-broker:latest \ + -f Dockerfile . + release: ## Create and push a new release tag (auto-increments patch version) @echo "Creating new release..." @latest_tag=$$(git describe --tags --abbrev=0 2>/dev/null || echo ""); \ diff --git a/pkg/broker/config/config.go b/pkg/broker/config/config.go index 7b26603..d1041df 100644 --- a/pkg/broker/config/config.go +++ b/pkg/broker/config/config.go @@ -4,8 +4,8 @@ import ( "fmt" "time" - "github.com/spf13/viper" "git.warky.dev/wdevs/pgsql-broker/pkg/broker/adapter" + "github.com/spf13/viper" ) // Config holds all broker configuration diff --git a/pkg/broker/install/install.go b/pkg/broker/install/install.go index 43cb532..2297a91 100644 --- a/pkg/broker/install/install.go +++ b/pkg/broker/install/install.go @@ -326,7 +326,7 @@ func execStatements(ctx context.Context, tx adapter.DBTransaction, sqlText strin // $$-quoted function bodies intact. // splitSQLStatements splits a SQL script into individual statements on // top-level semicolons, ignoring semicolons that appear inside single-quoted -// strings ('...', with '' as an escaped quote), double-quoted identifiers, +// strings ('...', with ” as an escaped quote), double-quoted identifiers, // line comments (--), and dollar-quoted bodies ($$...$$ or $tag$...$tag$). func splitSQLStatements(sqlText string) []string { var result []string diff --git a/pkg/broker/queue/queue.go b/pkg/broker/queue/queue.go index a7b4681..a121740 100644 --- a/pkg/broker/queue/queue.go +++ b/pkg/broker/queue/queue.go @@ -24,16 +24,16 @@ type Queue struct { // Config holds queue configuration type Config struct { - Number int - InstanceID int64 - WorkerCount int - DBAdapter adapter.DBAdapter - Logger adapter.Logger - BufferSize int - TimerSeconds int - FetchSize int - TenantID string - LeaseSeconds int + Number int + InstanceID int64 + WorkerCount int + DBAdapter adapter.DBAdapter + Logger adapter.Logger + BufferSize int + TimerSeconds int + FetchSize int + TenantID string + LeaseSeconds int } // New creates a new queue manager diff --git a/pkg/broker/worker/worker.go b/pkg/broker/worker/worker.go index f87c822..dcec69a 100644 --- a/pkg/broker/worker/worker.go +++ b/pkg/broker/worker/worker.go @@ -218,7 +218,7 @@ func (w *Worker) processJobs(ctx context.Context) { if jobID <= 0 { tx.Rollback() // No job found, rollback - return // No more jobs + return // No more jobs } // Run the job