Skip to content

Build and push Docker images #423

Build and push Docker images

Build and push Docker images #423

name: Build and push Docker images
on:
# Build images daily
schedule:
- cron: 0 0 * * *
push:
branches:
- master
paths:
- docker/**
pull_request:
branches:
- master
paths:
- docker/**
workflow_dispatch:
inputs:
force-rebuild:
type: boolean
description: Force rebuild (even if commit hash has already been built)
default: false
env:
REGISTRY: ghcr.io
IMAGE_NAME_SERVER: ${{ github.repository_owner }}/vmangos-server
IMAGE_NAME_DATABASE: ${{ github.repository_owner }}/vmangos-database
jobs:
setup:
name: Setup
runs-on: ubuntu-latest
outputs:
commit-hash: ${{ steps.latest-commit-hash.outputs.result }}
already-built: ${{ steps.already-built.outputs.result }}
steps:
- name: Get latest commit hash
uses: actions/github-script@v7
id: latest-commit-hash
with:
result-encoding: string
retries: 3
script: |
const ref = await github.rest.git.getRef({
owner: 'vmangos',
repo: 'core',
ref: 'heads/development',
})
return ref.data.object.sha
- name: Determine if images for commit hash have already been built
id: already-built
run: |
if [[ "${{ github.event.inputs.force-rebuild }}" == "true" ]]; then
echo "result=false" >> $GITHUB_OUTPUT
exit 0
fi
ghcr_token=$(echo ${{ secrets.GITHUB_TOKEN }} | base64)
tags=$(skopeo list-tags --registry-token ${ghcr_token} docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DATABASE }} | jq '.Tags[]')
if grep -q "${{ steps.latest-commit-hash.outputs.result }}" <<< "${tags}"; then
echo "result=true" >> $GITHUB_OUTPUT
exit 0
fi
echo "result=false" >> $GITHUB_OUTPUT
# If the original MariaDB entrypoint script changes, we can't guarantee
# that our custom version (which relies on functions defined in the
# original) will still work, so we fail the workflow run at this point.
- name: Check if MariaDB entrypoint script has been updated
id: mariadb-entrypoint-check
run: |
known_entrypoint=https://raw.githubusercontent.com/MariaDB/mariadb-docker/81c4ce79659a9b705686b5704a3f3d3b9119532a/11.4/docker-entrypoint.sh
latest_entrypoint=https://raw.githubusercontent.com/MariaDB/mariadb-docker/master/11.4/docker-entrypoint.sh
curl -o known-entrypoint.sh $known_entrypoint
curl -o latest-entrypoint.sh $latest_entrypoint
diff known-entrypoint.sh latest-entrypoint.sh
build-and-push-server-images:
name: Build and push server images
needs: setup
if: ${{ needs.setup.outputs.already-built != 'true' }}
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
client-version: [5875, 5464, 5302, 5086, 4878, 4695, 4544]
use-anticheat: [0, 1]
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Generate tags
uses: actions/github-script@v7
id: generate-tags
env:
COMMIT_HASH: ${{ needs.setup.outputs.commit-hash }}
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_SERVER }}
CLIENT_VERSION: ${{ matrix.client-version }}
USE_ANTICHEAT: ${{ matrix.use-anticheat }}
with:
result-encoding: string
script: |
const tags = []
const useAnticheat = parseInt(process.env.USE_ANTICHEAT) === 1
// We tag the newest non-anticheat build for client version 5875
// with `latest` since that can be considered the default
if (
parseInt(process.env.CLIENT_VERSION) === 5875 &&
!useAnticheat
) {
tags.push(`${process.env.IMAGE}:latest`)
}
const potentialAnticheatSuffix = useAnticheat
? '-anticheat'
: ''
tags.push(`${process.env.IMAGE}:${process.env.CLIENT_VERSION}${potentialAnticheatSuffix}`)
tags.push(`${process.env.IMAGE}:${process.env.CLIENT_VERSION}${potentialAnticheatSuffix}-${process.env.COMMIT_HASH}`)
return tags.join(',')
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push images
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64, linux/arm64
file: ./docker/server/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
provenance: false
build-args: |
VMANGOS_REVISION=${{ needs.setup.outputs.commit-hash }}
VMANGOS_CLIENT_VERSION=${{ matrix.client-version }}
VMANGOS_USE_ANTICHEAT=${{ matrix.use-anticheat }}
tags: ${{ steps.generate-tags.outputs.result }}
# Since the database image builds only take a few minutes (and therefore
# always complete before the server image builds), we need to build after the
# server images; otherwise, we would push new database images without knowing
# if the server image builds will succeed (and if there is, e.g., a
# compilation error due to a bug upstream we would end up with a version
# mismatch between the latest database images and the latest server images).
build-and-push-database-images:
name: Build and push database images
needs: [setup, build-and-push-server-images]
if: ${{ needs.setup.outputs.already-built != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Generate tags
uses: actions/github-script@v7
id: generate-tags
env:
COMMIT_HASH: ${{ needs.setup.outputs.commit-hash }}
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DATABASE }}
with:
result-encoding: string
script: |
const tags = []
tags.push(`${process.env.IMAGE}:latest`)
tags.push(`${process.env.IMAGE}:${process.env.COMMIT_HASH}`)
return tags.join(',')
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push images
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64, linux/arm64
file: ./docker/database/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
provenance: false
build-args: |
VMANGOS_REVISION=${{ needs.setup.outputs.commit-hash }}
tags: ${{ steps.generate-tags.outputs.result }}
delete-old-package-versions:
name: Delete old package versions
needs: [setup, build-and-push-server-images, build-and-push-database-images]
if: ${{ needs.setup.outputs.already-built != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Delete old server package versions
uses: actions/delete-package-versions@v5
with:
package-name: vmangos-server
package-type: container
# According to
# https://docs.github.com/en/enterprise-server@3.11/packages/working-with-a-github-packages-registry/working-with-the-npm-registry#limits-for-published-npm-versions
# there might at some point be a limit of 1,000 versions per package.
# It is not clear if that will only be applied to Enterprise and/or
# npm packages, but let's be safe and make sure we don't keep more
# than 1,000.
#
# We have 7 different server versions per build. For each version we
# have two variants (with and without anticheat support). Per variant
# we have two actual images in addition to the manifest, so
# 42 packages in total.
#
# 42 * 22 = 924 packages (which keeps us under the assumed limit of
# 1,000)
min-versions-to-keep: 924
- name: Delete old database package versions
uses: actions/delete-package-versions@v5
with:
package-name: vmangos-database
package-type: container
# Above, we have set it up to keep 22 builds worth of server images
# (to stay below that supposed 1,000 packages limit). We want to keep
# all the matching database images.
#
# Per database build we have 3 packages in total (the manifest plus
# two actual images).
#
# 3 * 22 = 66 packages
min-versions-to-keep: 66