Skip to content

deploy-image

deploy-image #215

Workflow file for this run

name: deploy-image
on:
workflow_dispatch:
workflow_run:
workflows:
- build-latest
branches:
- develop
types:
- completed
jobs:
deploy-image:
if: |
github.actor != 'dependabot[bot]' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'
)
)
runs-on: ubuntu-latest
timeout-minutes: 45
outputs:
push_dated: ${{ steps.publish_mode.outputs.push_dated }}
push_version: ${{ steps.publish_mode.outputs.push_version }}
release_type: ${{ steps.publish_mode.outputs.release_type }}
strategy:
matrix:
stablePluginBaseURL:
# Keep this here so that it is easy to override in future.
- https://sourceforge.net/projects/geoserver/files/GeoServer
geoserverPatchMajorVersionBugs:
# Do NOT normally update an existing GeoServer version tag for
# arbitrary code changes.
- no
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
ref: develop
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to DockerHub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Check latest GeoServer version
id: geoserver_check
shell: bash
run: |
set -euo pipefail
IMAGE_VERSION=3.12-slim
docker run --rm \
-v "$PWD/.github/workflows/scripts:/scripts" \
-v "$GITHUB_OUTPUT:/github_output/github_output.txt" \
python:${IMAGE_VERSION} \
bash /scripts/check_geoserver_version.sh
- name: Check Tomcat version in the series
id: tomcat_check
shell: bash
run: |
set -euo pipefail
IMAGE_VERSION=3.12-slim
docker run --rm \
-v "$PWD/.github/workflows/scripts:/scripts" \
-v "$GITHUB_OUTPUT:/github_output/github_output.txt" \
python:${IMAGE_VERSION} \
bash /scripts/check_tomcat_version.sh
# ------------------------------------------------------------
# Read metadata from the currently published GeoServer image.
#
# build_info.env contains:
#
# TOMCAT_VERSION=
# TOMCAT_DIGEST_SHA=
# GEOSERVER_VERSION=
#
# This is the state that the currently published image was
# actually built with.
# ------------------------------------------------------------
- name: Read published image metadata
id: published_image
shell: bash
run: |
set -euo pipefail
docker pull kartoza/geoserver:latest
CONTAINER_ID=$(docker create kartoza/geoserver:latest)
trap 'docker rm -f "${CONTAINER_ID}" >/dev/null 2>&1 || true' EXIT
docker cp \
"${CONTAINER_ID}:/etc/kartoza/build_info.env" \
./build_info.env
VERSION_INFO=$(cat ./build_info.env)
echo "Published image metadata:"
echo "$VERSION_INFO"
TOMCAT_VERSION=$(
echo "$VERSION_INFO" |
grep '^TOMCAT_VERSION=' |
cut -d= -f2-
)
TOMCAT_VERSION_DIGEST=$(
echo "$VERSION_INFO" |
grep '^TOMCAT_DIGEST_SHA=' |
cut -d= -f2-
)
GEOSERVER_VERSION=$(
echo "$VERSION_INFO" |
grep '^GEOSERVER_VERSION=' |
cut -d= -f2-
)
echo "TOMCAT_VERSION=$TOMCAT_VERSION" \
>> "$GITHUB_OUTPUT"
echo "TOMCAT_VERSION_DIGEST=$TOMCAT_VERSION_DIGEST" \
>> "$GITHUB_OUTPUT"
echo "GEOSERVER_VERSION=$GEOSERVER_VERSION" \
>> "$GITHUB_OUTPUT"
# ------------------------------------------------------------
# Resolve the digest currently associated with the same Tomcat
# tag that the published GeoServer image was built from.
#
# This detects mutable Tomcat/base-image updates where:
#
# TOMCAT_VERSION stays the same
# TOMCAT_DIGEST_SHA changes
# ------------------------------------------------------------
- name: Published Tomcat Digest
id: tomcat_digest_comparison
shell: bash
run: |
set -euo pipefail
PUBLISHED_TOMCAT="${{ steps.published_image.outputs.TOMCAT_VERSION }}"
docker pull "tomcat:${PUBLISHED_TOMCAT}"
TOMCAT_DIGEST=$(
docker inspect \
--format='{{index .RepoDigests 0}}' \
"tomcat:${PUBLISHED_TOMCAT}"
)
echo "Current digest for published Tomcat tag:"
echo "${TOMCAT_DIGEST}"
echo "tomcat_sha=${TOMCAT_DIGEST}" \
>> "$GITHUB_OUTPUT"
# ------------------------------------------------------------
# Resolve the Tomcat digest that THIS build will actually use.
#
# This can be different from the previous step if the Tomcat
# version itself has moved.
# ------------------------------------------------------------
- name: Tomcat Digest for image used in build
id: tomcat_digest
shell: bash
run: |
set -euo pipefail
BUILD_TOMCAT="${{ steps.tomcat_check.outputs.tomcat_version }}"
docker pull "tomcat:${BUILD_TOMCAT}"
TOMCAT_DIGEST=$(
docker inspect \
--format='{{index .RepoDigests 0}}' \
"tomcat:${BUILD_TOMCAT}"
)
echo "Tomcat digest for new build:"
echo "${TOMCAT_DIGEST}"
echo "tomcat_sha=${TOMCAT_DIGEST}" \
>> "$GITHUB_OUTPUT"
# ------------------------------------------------------------
# Check whether the semantic GeoServer tag exists.
#
# Normally version differences already tell us this is a new
# release, but this also repairs a missing version tag.
# ------------------------------------------------------------
- name: Check if GeoServer version tag exists on Docker Hub
id: check_hub_image_exists
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.${{ steps.geoserver_check.outputs.bugfix }}"
STATUS=$(
curl -s \
-o /dev/null \
-w "%{http_code}" \
"https://hub.docker.com/v2/repositories/kartoza/geoserver/tags/${VERSION}/"
)
echo "Docker Hub status for ${VERSION}: ${STATUS}"
if [[ "${STATUS}" == "200" ]]; then
echo "image_exists=true" >> "$GITHUB_OUTPUT"
else
echo "image_exists=false" >> "$GITHUB_OUTPUT"
fi
# ------------------------------------------------------------
# Decide which tags should move.
#
# MODE 1: New GeoServer version
# latest -> YES
# 2.x.x -> YES
# dated -> YES
#
# MODE 2: Tomcat version/digest changed
# latest -> YES
# 2.x.x -> YES
# dated -> NO
#
# MODE 3: Normal repository/code change
# latest -> YES
# 2.x.x -> NO
# dated -> YES
#
# Explicit geoserverPatchMajorVersionBugs=yes can still force
# the semantic GeoServer tag to be refreshed.
# ------------------------------------------------------------
- name: Determine image publishing mode
id: publish_mode
shell: bash
run: |
set -euo pipefail
CURRENT_GEOSERVER="${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.${{ steps.geoserver_check.outputs.bugfix }}"
PUBLISHED_GEOSERVER="${{ steps.published_image.outputs.GEOSERVER_VERSION }}"
CURRENT_TOMCAT="${{ steps.tomcat_check.outputs.tomcat_version }}"
PUBLISHED_TOMCAT="${{ steps.published_image.outputs.TOMCAT_VERSION }}"
PUBLISHED_TOMCAT_DIGEST="${{ steps.published_image.outputs.TOMCAT_VERSION_DIGEST }}"
DOCKERHUB_PUBLISHED_TOMCAT_DIGEST="${{ steps.tomcat_digest_comparison.outputs.tomcat_sha }}"
VERSION_TAG_EXISTS="${{ steps.check_hub_image_exists.outputs.image_exists }}"
PATCH_MAJOR_BUGS="${{ matrix.geoserverPatchMajorVersionBugs }}"
echo "----------------------------------------"
echo "Published GeoServer: ${PUBLISHED_GEOSERVER}"
echo "Current GeoServer: ${CURRENT_GEOSERVER}"
echo
echo "Published Tomcat: ${PUBLISHED_TOMCAT}"
echo "Current Tomcat: ${CURRENT_TOMCAT}"
echo
echo "Published Tomcat digest: ${PUBLISHED_TOMCAT_DIGEST}"
echo "Docker Hub Tomcat digest: ${DOCKERHUB_PUBLISHED_TOMCAT_DIGEST}"
echo
echo "Version tag exists: ${VERSION_TAG_EXISTS}"
echo "Patch existing version: ${PATCH_MAJOR_BUGS}"
echo "----------------------------------------"
GEOSERVER_CHANGED=false
TOMCAT_VERSION_CHANGED=false
TOMCAT_DIGEST_CHANGED=false
BASE_IMAGE_CHANGED=false
if [[ "${PUBLISHED_GEOSERVER}" != "${CURRENT_GEOSERVER}" ]]; then
GEOSERVER_CHANGED=true
fi
if [[ "${PUBLISHED_TOMCAT}" != "${CURRENT_TOMCAT}" ]]; then
TOMCAT_VERSION_CHANGED=true
fi
if [[ "${PUBLISHED_TOMCAT_DIGEST}" != "${DOCKERHUB_PUBLISHED_TOMCAT_DIGEST}" ]]; then
TOMCAT_DIGEST_CHANGED=true
fi
if [[ "${TOMCAT_VERSION_CHANGED}" == "true" ]] ||
[[ "${TOMCAT_DIGEST_CHANGED}" == "true" ]]; then
BASE_IMAGE_CHANGED=true
fi
#
# latest is ALWAYS published.
#
PUSH_VERSION=false
PUSH_DATED=true
RELEASE_TYPE=code-change
#
# New GeoServer release.
#
if [[ "${GEOSERVER_CHANGED}" == "true" ]]; then
echo "Publishing mode: new GeoServer release"
PUSH_VERSION=true
PUSH_DATED=true
RELEASE_TYPE=geoserver-release
#
# Existing GeoServer version, but the Tomcat image itself
# has changed.
#
elif [[ "${BASE_IMAGE_CHANGED}" == "true" ]]; then
echo "Publishing mode: Tomcat/base-image refresh"
PUSH_VERSION=true
PUSH_DATED=false
RELEASE_TYPE=base-image-refresh
#
# Repair a semantic tag if it has disappeared.
#
elif [[ "${VERSION_TAG_EXISTS}" != "true" ]]; then
echo "Publishing mode: missing GeoServer version tag"
PUSH_VERSION=true
PUSH_DATED=true
RELEASE_TYPE=missing-version-tag
#
# Explicit override.
#
elif [[ "${PATCH_MAJOR_BUGS}" == "yes" ]]; then
echo "Publishing mode: explicitly patch existing GeoServer version"
PUSH_VERSION=true
PUSH_DATED=true
RELEASE_TYPE=version-patch
#
# Otherwise this is an ordinary repository/code change.
#
else
echo "Publishing mode: normal repository/code change"
PUSH_VERSION=false
PUSH_DATED=true
RELEASE_TYPE=code-change
fi
echo "----------------------------------------"
echo "push latest: true"
echo "push version: ${PUSH_VERSION}"
echo "push dated: ${PUSH_DATED}"
echo "release type: ${RELEASE_TYPE}"
echo "----------------------------------------"
echo "push_version=${PUSH_VERSION}" \
>> "$GITHUB_OUTPUT"
echo "push_dated=${PUSH_DATED}" \
>> "$GITHUB_OUTPUT"
echo "release_type=${RELEASE_TYPE}" \
>> "$GITHUB_OUTPUT"
echo "base_image_changed=${BASE_IMAGE_CHANGED}" \
>> "$GITHUB_OUTPUT"
# ------------------------------------------------------------
# Remaining build information
# ------------------------------------------------------------
- name: Check Java Home path
id: java_home_check
shell: bash
run: |
set -euo pipefail
IMAGE_VERSION="${{ steps.tomcat_check.outputs.tomcat_version }}"
JAVA_HOME=$(
docker run --rm \
"tomcat:${IMAGE_VERSION}" \
sh -c 'printf "%s" "$JAVA_HOME"'
)
echo "${JAVA_HOME}"
echo "java_home=${JAVA_HOME}" \
>> "$GITHUB_OUTPUT"
- name: Check GDAL version
id: gdal_version_check
shell: bash
run: |
set -euo pipefail
IMAGE_VERSION="${{ steps.tomcat_check.outputs.tomcat_version }}"
docker run --rm \
-v "$PWD/.github/workflows/scripts:/scripts" \
-v "$GITHUB_OUTPUT:/github_output/github_output.txt" \
"tomcat:${IMAGE_VERSION}" \
bash /scripts/get_gdal_version.sh
- name: Get Current Date
id: current_date
shell: bash
run: |
echo "formatted=$(date -u +%Y.%m.%d)" \
>> "$GITHUB_OUTPUT"
# ------------------------------------------------------------
# Build and publish
# ------------------------------------------------------------
- name: Build prod image
id: docker_build_prod
timeout-minutes: 45
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm64
file: Dockerfile
push: true
tags: |
${{ secrets.DOCKERHUB_REPO }}/geoserver:latest
${{ steps.publish_mode.outputs.push_version == 'true' && format('{0}/geoserver:{1}.{2}.{3}', secrets.DOCKERHUB_REPO, steps.geoserver_check.outputs.major, steps.geoserver_check.outputs.minor, steps.geoserver_check.outputs.bugfix) || '' }}
${{ steps.publish_mode.outputs.push_dated == 'true' && format('{0}/geoserver:{1}.{2}.{3}--v{4}', secrets.DOCKERHUB_REPO, steps.geoserver_check.outputs.major, steps.geoserver_check.outputs.minor, steps.geoserver_check.outputs.bugfix, steps.current_date.outputs.formatted) || '' }}
build-args: |
IMAGE_VERSION=${{ steps.tomcat_check.outputs.tomcat_version }}
JAVA_HOME=${{ steps.java_home_check.outputs.java_home }}
GS_VERSION=${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.${{ steps.geoserver_check.outputs.bugfix }}
GS_VERSION_COMMUNITY=${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.0
WAR_URL=https://downloads.sourceforge.net/project/geoserver/GeoServer/${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.${{ steps.geoserver_check.outputs.bugfix }}/geoserver-${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.${{ steps.geoserver_check.outputs.bugfix }}-war.zip
STABLE_PLUGIN_BASE_URL=${{ matrix.stablePluginBaseURL }}
GDAL_VERSION=${{ steps.gdal_version_check.outputs.gdal_version }}
TOMCAT_IMAGE_SHA=${{ steps.tomcat_digest.outputs.tomcat_sha }}
COMMUNITY_EXTENSION_PLUGIN_BASE_URL=https://build.geoserver.org/geoserver/${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.x/community-latest
cache-from: |
type=gha,scope=prod
cache-to: |
type=gha,scope=prod,mode=max
target: geoserver-prod
# ==================================================================
# GitHub release
#
# A base-image-only refresh intentionally does NOT produce a dated
# Docker image and therefore does NOT produce another GitHub release.
# ==================================================================
publish_release_artifacts:
runs-on: ubuntu-latest
timeout-minutes: 15
needs:
- deploy-image
if: |
always() &&
needs.deploy-image.result == 'success' &&
needs.deploy-image.outputs.push_dated == 'true' &&
github.actor != 'dependabot[bot]' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'
)
)
steps:
- name: Checkout code
id: git_checkout
uses: actions/checkout@v7
with:
ref: develop
- name: Get Current Date
id: current_date
shell: bash
run: |
echo "formatted=$(date -u +%Y.%m.%d)" \
>> "$GITHUB_OUTPUT"
- name: Check latest GeoServer version
id: geoserver_check
shell: bash
run: |
set -euo pipefail
docker run --rm \
-v "$PWD/.github/workflows/scripts:/scripts" \
-v "$GITHUB_OUTPUT:/github_output/github_output.txt" \
python:3.12-slim \
bash /scripts/check_geoserver_version.sh
- name: Get Latest Commit Hash
id: latest_commit_hash
shell: bash
run: |
echo "commit=$(git rev-parse --short HEAD)" \
>> "$GITHUB_OUTPUT"
- name: Publish release
id: tag_releases
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
VERSION="${{ steps.geoserver_check.outputs.major }}.${{ steps.geoserver_check.outputs.minor }}.${{ steps.geoserver_check.outputs.bugfix }}"
DATE="${{ steps.current_date.outputs.formatted }}"
COMMIT="${{ steps.latest_commit_hash.outputs.commit }}"
RELEASE_TAG="v${VERSION}--${DATE}--${COMMIT}"
echo "Release type: ${{ needs.deploy-image.outputs.release_type }}"
echo "Creating release: ${RELEASE_TAG}"
#
# Avoid failing if this exact workflow is manually re-run.
#
if gh release view \
"${RELEASE_TAG}" \
--repo "$GITHUB_REPOSITORY" \
>/dev/null 2>&1; then
echo "Release ${RELEASE_TAG} already exists."
exit 0
fi
gh release create \
"${RELEASE_TAG}" \
--notes "${COMMIT}" \
--target develop \
--repo "$GITHUB_REPOSITORY"