Files

287 lines
9.4 KiB
YAML

name: Docker Images
on:
push:
tags:
- v*
# Manual runs validate the complete build without publishing mutable tags.
# To republish a release, run the workflow against its existing v* tag.
workflow_dispatch:
permissions:
contents: read
concurrency:
group: docker-image-${{ github.ref }}
cancel-in-progress: false
env:
PROFILE: pro
DOCKER_REGISTRY_DEFAULT: pnoker
DOCKER_REGISTRY_ALIYUN: registry.cn-beijing.aliyuncs.com/dc3
jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
publish: ${{ steps.variables.outputs.publish }}
service_version: ${{ steps.variables.outputs.service_version }}
service_series: ${{ steps.variables.outputs.service_series }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Validate release identity
id: variables
run: |
set -euo pipefail
VERSION=$(awk -F'[<>]' '/<parent>/,/<\/parent>/{if($2=="version") print $3}' pom.xml | head -1)
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid project version in pom.xml: $VERSION" >&2
exit 1
fi
SERIES="${VERSION%.*}"
PUBLISH=false
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
EXPECTED_TAG="v$VERSION"
if [[ "$GITHUB_REF_NAME" != "$EXPECTED_TAG" ]]; then
echo "Release tag '$GITHUB_REF_NAME' does not match pom.xml version '$EXPECTED_TAG'." >&2
exit 1
fi
PUBLISH=true
fi
echo "publish=$PUBLISH" >> "$GITHUB_OUTPUT"
echo "service_version=$VERSION" >> "$GITHUB_OUTPUT"
echo "service_series=$SERIES" >> "$GITHUB_OUTPUT"
verify-backend:
uses: ./.github/workflows/test.yml
verify-web:
uses: ./.github/workflows/ci-web.yml
build-backend:
needs:
- validate
- verify-backend
- verify-web
runs-on: ubuntu-latest
timeout-minutes: 180
environment: release
permissions:
contents: read
actions: write # for GitHub Actions cache (--cache-to type=gha)
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Set QEMU
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8
- name: Set Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c
- name: Login Docker Default Registry
if: needs.validate.outputs.publish == 'true'
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login Docker Aliyun Registry
if: needs.validate.outputs.publish == 'true'
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0
with:
registry: registry.cn-beijing.aliyuncs.com
username: ${{ vars.ALIYUN_DOCKERHUB_USERNAME }}
password: ${{ secrets.ALIYUN_DOCKERHUB_TOKEN }}
- name: Build backend images
env:
PUBLISH: ${{ needs.validate.outputs.publish }}
SERVICE_VERSION: ${{ needs.validate.outputs.service_version }}
SERVICE_SERIES: ${{ needs.validate.outputs.service_series }}
run: |
set -euo pipefail
services=(
dc3-gateway
dc3-center-agentic
dc3-center-auth
dc3-center-data
dc3-center-manager
dc3-center-single
dc3-driver-listening-virtual
dc3-driver-modbus-tcp
dc3-driver-modbus-rtu
dc3-driver-mqtt
dc3-driver-opc-da
dc3-driver-opc-ua
dc3-driver-plcs7
dc3-driver-virtual
dc3-driver-bacnet-ip
dc3-driver-ble
dc3-driver-can
dc3-driver-coap
dc3-driver-dlms
dc3-driver-ethernet-ip
dc3-driver-fins
dc3-driver-http
dc3-driver-iec104
dc3-driver-lwm2m
dc3-driver-melsec
dc3-driver-mysql
dc3-driver-oracle
dc3-driver-postgresql
dc3-driver-serial
dc3-driver-sl651
dc3-driver-snmp
dc3-driver-sqlserver
dc3-driver-tcp-udp
dc3-driver-zigbee
)
for name in "${services[@]}"; do
output_args=(--output=type=cacheonly)
tag_args=()
if [[ "$PUBLISH" == "true" ]]; then
output_args=(--push)
tag_args=(
--tag "$DOCKER_REGISTRY_DEFAULT/$name:latest"
--tag "$DOCKER_REGISTRY_DEFAULT/$name:$SERVICE_SERIES"
--tag "$DOCKER_REGISTRY_DEFAULT/$name:$SERVICE_VERSION"
--tag "$DOCKER_REGISTRY_ALIYUN/$name:latest"
--tag "$DOCKER_REGISTRY_ALIYUN/$name:$SERVICE_SERIES"
--tag "$DOCKER_REGISTRY_ALIYUN/$name:$SERVICE_VERSION"
)
fi
echo "Building $name (publish=$PUBLISH)"
# Single root-level Dockerfile defines a target stage per service.
# The shared `builder` stage (mvn package) runs ONCE for the
# whole reactor; BuildKit reuses it across every target image.
# GHA cache (type=gha) persists the builder stage between runs so
# subsequent CI invocations only rebuild what actually changed.
docker buildx build \
--platform linux/arm64,linux/amd64 \
--file Dockerfile \
--target "$name" \
--build-arg PROFILE="$PROFILE" \
--cache-from type=gha,scope=dc3-builder \
--cache-to type=gha,scope=dc3-builder,mode=max \
"${output_args[@]}" \
"${tag_args[@]}" \
.
done
build-web:
needs:
- validate
- verify-backend
- verify-web
runs-on: ubuntu-latest
timeout-minutes: 60
environment: release
permissions:
contents: read
actions: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Set QEMU
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8
- name: Set Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c
- name: Login DockerHub
if: needs.validate.outputs.publish == 'true'
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login Aliyun Registry
if: needs.validate.outputs.publish == 'true'
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0
with:
registry: registry.cn-beijing.aliyuncs.com
username: ${{ vars.ALIYUN_DOCKERHUB_USERNAME }}
password: ${{ secrets.ALIYUN_DOCKERHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302
with:
images: |
pnoker/dc3-web
registry.cn-beijing.aliyuncs.com/dc3/dc3-web
tags: |
type=match,pattern=v(.*),group=1
type=raw,value=latest
- name: Build web image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: .
file: dc3-web/Dockerfile
push: ${{ needs.validate.outputs.publish == 'true' }}
platforms: linux/arm64,linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=dc3-web
cache-to: type=gha,scope=dc3-web,mode=max
release:
runs-on: ubuntu-latest
needs:
- build-backend
- build-web
- validate
if: startsWith(github.ref, 'refs/tags/v')
timeout-minutes: 20
environment: release
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
- name: Generate release notes
id: release_notes
env:
SERVICE_VERSION: ${{ needs.validate.outputs.service_version }}
SERVICE_WORKSPACE: ${{ github.workspace }}
run: |
set -euo pipefail
{
echo "release_notes<<RELEASE_NOTES_EOF"
echo ""
perl -pe 's/\$\{SERVICE_VERSION\}/$ENV{SERVICE_VERSION}/g' "$SERVICE_WORKSPACE/dc3/doc/TITLE.md"
echo ""
perl -pe 's/\$\{SERVICE_VERSION\}/$ENV{SERVICE_VERSION}/g' "$SERVICE_WORKSPACE/dc3/doc/CHANGE.md"
echo ""
perl -pe 's/\$\{SERVICE_VERSION\}/$ENV{SERVICE_VERSION}/g' "$SERVICE_WORKSPACE/dc3/doc/RELEASE-FOOTER.md"
echo "RELEASE_NOTES_EOF"
} >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228
with:
name: ${{ needs.validate.outputs.service_version }}
body: ${{ steps.release_notes.outputs.release_notes }}
tag_name: ${{ github.ref_name }}
draft: false
prerelease: false
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}