Skip to content

publish self-host docker v1.5.33 #57

publish self-host docker v1.5.33

publish self-host docker v1.5.33 #57

name: Publish Self-host Docker Image
run-name: "${{ format('publish self-host docker {0}', inputs.tag) }}"
on:
workflow_dispatch:
inputs:
tag:
description: Git tag to publish (e.g. v1.5.0)
required: true
type: string
permissions:
contents: read
concurrency:
group: publish-selfhost-docker-${{ inputs.tag }}
cancel-in-progress: false
jobs:
metadata:
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: read
outputs:
release_tag: ${{ steps.validate.outputs.tag }}
image: ${{ steps.image.outputs.image }}
tags: ${{ steps.image.outputs.tags }}
legacy_tags: ${{ steps.image.outputs.legacy_tags }}
labels: ${{ steps.image.outputs.labels }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.11
- name: Validate release tag
id: validate
env:
RAW_RELEASE_TAG: ${{ inputs.tag }}
run: bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG --output tag
- name: Checkout release tag
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT || github.token }}
run: |
auth_remote="https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git fetch --force --tags "$auth_remote" "refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG"
git checkout --detach "$RELEASE_TAG"
- name: Resolve image metadata
id: image
shell: bash
run: |
set -euo pipefail
version="${RELEASE_TAG#v}"
owner="$(printf '%s' "$GITHUB_REPOSITORY_OWNER" | tr '[:upper:]' '[:lower:]')"
image="ghcr.io/${owner}/executor-selfhost"
legacy_image="ghcr.io/rhyssullivan/executor-selfhost"
revision="$(git rev-parse HEAD)"
if [[ "$version" == *-* ]]; then
channel="beta"
else
channel="latest"
fi
{
echo "image=$image"
echo "version=$version"
echo "channel=$channel"
echo "tags<<TAGS"
echo "${image}:${RELEASE_TAG}"
echo "${image}:${version}"
echo "${image}:${channel}"
echo "TAGS"
echo "legacy_tags<<TAGS"
echo "${legacy_image}:${RELEASE_TAG}"
echo "${legacy_image}:${version}"
echo "${legacy_image}:${channel}"
echo "TAGS"
echo "labels<<LABELS"
echo "org.opencontainers.image.title=Executor self-host"
echo "org.opencontainers.image.description=Single-container self-hosted Executor"
echo "org.opencontainers.image.source=https://github.com/${GITHUB_REPOSITORY}"
echo "org.opencontainers.image.revision=${revision}"
echo "org.opencontainers.image.version=${version}"
echo "LABELS"
} >> "$GITHUB_OUTPUT"
build:
needs: metadata
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
platform: linux/amd64
runner: blacksmith-4vcpu-ubuntu-2404
- arch: arm64
platform: linux/arm64
runner: blacksmith-4vcpu-ubuntu-2404-arm
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
steps:
- name: Checkout release tag
uses: actions/checkout@v4
with:
ref: ${{ needs.metadata.outputs.release_tag }}
fetch-depth: 0
persist-credentials: false
- name: Setup Blacksmith Builder
uses: useblacksmith/setup-docker-builder@v1
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push self-host image by digest
id: build
uses: useblacksmith/build-push-action@v2
with:
context: .
file: apps/host-selfhost/Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ needs.metadata.outputs.labels }}
outputs: type=image,name=${{ needs.metadata.outputs.image }},push-by-digest=true,name-canonical=true,push=true
- name: Export image digest
shell: bash
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
set -euo pipefail
if [ -z "$DIGEST" ]; then
echo "Build did not return a digest."
exit 1
fi
mkdir -p "$RUNNER_TEMP/digests"
touch "$RUNNER_TEMP/digests/${DIGEST#sha256:}"
- name: Upload image digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
# Release gate: run the full selfhost-docker e2e project against the exact
# by-digest image each build leg pushed, before any user-visible tag moves.
# Build-only smoke misses startup crashes and feature-path breaks (a package
# resolved at runtime but missing from the packaged runtime shipped broken in
# v1.5.30 exactly this way); per-arch matters too — the libsql native-addon
# bug was arm64-only.
e2e:
needs:
- metadata
- build
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: blacksmith-4vcpu-ubuntu-2404
- arch: arm64
runner: blacksmith-4vcpu-ubuntu-2404-arm
runs-on: ${{ matrix.runner }}
timeout-minutes: 40
permissions:
contents: read
packages: read
steps:
- name: Checkout release tag
uses: actions/checkout@v4
with:
ref: ${{ needs.metadata.outputs.release_tag }}
persist-credentials: false
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.11
- name: Cache Bun package cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-${{ runner.arch }}-bun-1.3.11-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-bun-1.3.11-
# Scenario helpers spawn Node sidecars; pin the same Node 24 runtime the
# other workflows use.
- uses: actions/setup-node@v4
with:
node-version: 24
- run: bun install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-${{ runner.arch }}-playwright-1.60.0
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-playwright-
# Install from e2e so bunx resolves ITS pinned playwright (the version
# the tests run against) rather than floating to the latest.
- name: Install Playwright Chromium
run: bunx playwright install --with-deps chromium chromium-headless-shell
working-directory: e2e
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download image digest
uses: actions/download-artifact@v4
with:
name: digests-${{ matrix.arch }}
path: ${{ runner.temp }}/digests
- name: Resolve image reference
id: image_ref
shell: bash
env:
IMAGE: ${{ needs.metadata.outputs.image }}
run: |
set -euo pipefail
digest_file="$(find "$RUNNER_TEMP/digests" -maxdepth 1 -type f | head -n 1)"
if [ -z "$digest_file" ]; then
echo "No image digest was downloaded."
exit 1
fi
ref="${IMAGE}@sha256:$(basename "$digest_file")"
echo "ref=$ref" >> "$GITHUB_OUTPUT"
docker pull "$ref"
- name: Run selfhost-docker scenarios against the published digest
env:
E2E_SELFHOST_DOCKER_IMAGE: ${{ steps.image_ref.outputs.ref }}
run: bunx vitest run --project selfhost-docker --retry=2
working-directory: e2e
- name: Upload run artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e-runs-selfhost-docker-${{ matrix.arch }}
path: |
e2e/runs/
e2e/selfhost-docker.boot.log
retention-days: 7
merge:
needs:
- metadata
- build
- e2e
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
packages: write
env:
HAS_LEGACY_TOKEN: ${{ secrets.GHCR_LEGACY_TOKEN != '' }}
steps:
- name: Download image digests
uses: actions/download-artifact@v4
with:
pattern: digests-*
path: ${{ runner.temp }}/digests
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Publish multi-arch self-host image
shell: bash
env:
IMAGE: ${{ needs.metadata.outputs.image }}
TAGS: ${{ needs.metadata.outputs.tags }}
run: |
set -euo pipefail
sources=()
while IFS= read -r digest_file; do
digest="$(basename "$digest_file")"
[[ -n "$digest" ]] || continue
sources+=("${IMAGE}@sha256:${digest}")
done < <(find "$RUNNER_TEMP/digests" -maxdepth 1 -type f | sort)
if [ "${#sources[@]}" -eq 0 ]; then
echo "No image digests were downloaded."
exit 1
fi
tag_args=()
while IFS= read -r tag; do
[[ -n "$tag" ]] || continue
tag_args+=("-t" "$tag")
done <<< "$TAGS"
docker buildx imagetools create "${tag_args[@]}" "${sources[@]}"
- name: Skip legacy GHCR mirror (GHCR_LEGACY_TOKEN not configured)
if: env.HAS_LEGACY_TOKEN != 'true'
run: echo "GHCR_LEGACY_TOKEN is not configured; skipping legacy GHCR mirror."
- name: Log in to legacy GHCR namespace
if: env.HAS_LEGACY_TOKEN == 'true'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: rhyssullivan
password: ${{ secrets.GHCR_LEGACY_TOKEN }}
- name: Mirror self-host image to legacy GHCR namespace
if: env.HAS_LEGACY_TOKEN == 'true'
shell: bash
env:
SOURCE_IMAGE: ${{ needs.metadata.outputs.image }}:${{ needs.metadata.outputs.release_tag }}
LEGACY_TAGS: ${{ needs.metadata.outputs.legacy_tags }}
run: |
set -euo pipefail
tag_args=()
while IFS= read -r tag; do
[[ -n "$tag" ]] || continue
tag_args+=("-t" "$tag")
done <<< "$LEGACY_TAGS"
docker buildx imagetools create "${tag_args[@]}" "$SOURCE_IMAGE"