Skip to content

v4.6.1

v4.6.1 #609

Workflow file for this run

name: Docker Build and Publish
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version to build (e.g., 2.21.2-test)'
required: true
default: 'test'
env:
REGISTRY: ghcr.io
jobs:
# Build for amd64 and arm64 using Node.js 24 (Alpine)
build-main:
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version and image name
id: meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${GITHUB_REF#refs/tags/v}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "image=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Build and push (amd64, arm64)
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-main
labels: |
org.opencontainers.image.description=Web tool for monitoring a Meshtastic Node Deployment over TCP/HTTP
cache-from: type=gha,scope=main
cache-to: type=gha,mode=max,scope=main
provenance: true
sbom: true
timeout-minutes: 40
# Build for armv7 using Node.js 22 (Debian slim)
build-armv7:
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version and image name
id: meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${GITHUB_REF#refs/tags/v}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "image=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Build and push (armv7)
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile.armv7
platforms: linux/arm/v7
push: true
tags: ${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-armv7
labels: |
org.opencontainers.image.description=Web tool for monitoring a Meshtastic Node Deployment over TCP/HTTP
cache-from: type=gha,scope=armv7
cache-to: type=gha,mode=max,scope=armv7
provenance: true
sbom: true
timeout-minutes: 40
# Smoke test: verify critical files are non-zero in each platform image
# Prevents publishing broken images (see issue #2046)
smoke-test:
runs-on: ubuntu-latest
needs: [build-main, build-armv7]
timeout-minutes: 15
permissions:
contents: read
packages: read
strategy:
fail-fast: true
matrix:
include:
- tag_suffix: main
platform: linux/amd64
- tag_suffix: main
platform: linux/arm64
- tag_suffix: armv7
platform: linux/arm/v7
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version and image name
id: meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${GITHUB_REF#refs/tags/v}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "image=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Verify critical files are non-zero
run: |
IMAGE="${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-${{ matrix.tag_suffix }}"
PLATFORM="${{ matrix.platform }}"
echo "Smoke testing $IMAGE ($PLATFORM)"
echo "─────────────────────────────────────"
# Pull the image for this specific platform
docker pull --platform "$PLATFORM" "$IMAGE"
# Critical files that must be non-zero
FILES=(
"/usr/local/bin/docker-entrypoint.sh"
"/app/dist/server/server.js"
"/app/package.json"
"/etc/supervisord.conf"
)
FAILED=0
for FILE in "${FILES[@]}"; do
SIZE=$(docker run --rm --entrypoint stat --platform "$PLATFORM" "$IMAGE" -c%s "$FILE" 2>/dev/null || echo "MISSING")
if [ "$SIZE" = "MISSING" ]; then
echo "FAIL: $FILE is missing"
FAILED=1
elif [ "$SIZE" = "0" ]; then
echo "FAIL: $FILE is 0 bytes"
FAILED=1
else
echo " OK: $FILE ($SIZE bytes)"
fi
done
# Verify node binary runs
NODE_VERSION=$(docker run --rm --entrypoint node --platform "$PLATFORM" "$IMAGE" --version 2>/dev/null || echo "FAILED")
if [[ "$NODE_VERSION" == v* ]]; then
echo " OK: node $NODE_VERSION"
else
echo "FAIL: node binary not functional"
FAILED=1
fi
echo "─────────────────────────────────────"
if [ "$FAILED" -ne 0 ]; then
echo "SMOKE TEST FAILED for $PLATFORM"
exit 1
fi
echo "Smoke test passed for $PLATFORM"
# Create multi-arch manifest combining all platforms
create-manifest:
runs-on: ubuntu-latest
needs: [build-main, build-armv7, smoke-test]
permissions:
contents: read
packages: write
steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check if release is a pre-release
id: check_prerelease
run: |
if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
fi
- name: Extract version components and image name
id: meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${GITHUB_REF#refs/tags/v}"
fi
MAJOR=$(echo $VERSION | cut -d. -f1)
MINOR=$(echo $VERSION | cut -d. -f2)
IMAGE=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "major=$MAJOR" >> $GITHUB_OUTPUT
echo "minor=$MAJOR.$MINOR" >> $GITHUB_OUTPUT
echo "image=$IMAGE" >> $GITHUB_OUTPUT
- name: Create and push manifest for version tag
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }} \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-main \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-armv7
- name: Create and push manifest for minor version tag
if: github.event_name == 'release'
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.minor }} \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-main \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-armv7
- name: Create and push manifest for major version tag
if: github.event_name == 'release'
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.major }} \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-main \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-armv7
- name: Create and push manifest for latest tag
if: github.event_name == 'release' && steps.check_prerelease.outputs.is_prerelease == 'false'
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:latest \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-main \
${{ env.REGISTRY }}/${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.version }}-armv7
- name: Clean up intermediate tags
continue-on-error: true
run: |
# Note: GHCR doesn't support deleting tags via API easily
# The intermediate tags (-main, -armv7) will remain but won't affect users
echo "Intermediate tags created: ${{ steps.meta.outputs.version }}-main, ${{ steps.meta.outputs.version }}-armv7"
echo "These are combined into the main manifest tags"