201 lines
7.0 KiB
YAML
201 lines
7.0 KiB
YAML
name: Release Smoke
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
paperclip_version:
|
|
description: Published Paperclip dist-tag to test
|
|
required: true
|
|
default: canary
|
|
type: choice
|
|
options:
|
|
- canary
|
|
- nightly
|
|
- beta
|
|
- latest
|
|
host_port:
|
|
description: Host port for the Docker smoke container
|
|
required: false
|
|
default: "3232"
|
|
type: string
|
|
artifact_name:
|
|
description: Artifact name for uploaded diagnostics
|
|
required: false
|
|
default: release-smoke
|
|
type: string
|
|
workflow_call:
|
|
inputs:
|
|
paperclip_version:
|
|
required: true
|
|
type: string
|
|
host_port:
|
|
required: false
|
|
default: "3232"
|
|
type: string
|
|
artifact_name:
|
|
required: false
|
|
default: release-smoke
|
|
type: string
|
|
|
|
jobs:
|
|
# The Docker smoke below can never exercise the background-service leg of
|
|
# onboarding: containers have no service manager, so v2026.824.0 shipped a
|
|
# service install that crash-looped on a missing shim while every
|
|
# golden-path check stayed green. Run the same published artifact directly
|
|
# on the runner VM's systemd and require the installed service to end up
|
|
# serving.
|
|
smoke_service:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v7
|
|
with:
|
|
node-version: 24
|
|
|
|
- name: Start a user systemd session
|
|
# The hosted runner has no login session for the runner user, so
|
|
# `systemctl --user` cannot reach a user manager until lingering
|
|
# starts one. Export the session address for the steps below.
|
|
run: |
|
|
sudo loginctl enable-linger "$(id -un)"
|
|
uid="$(id -u)"
|
|
for _ in $(seq 1 30); do
|
|
[[ -S "/run/user/$uid/bus" ]] && break
|
|
sleep 1
|
|
done
|
|
[[ -S "/run/user/$uid/bus" ]]
|
|
{
|
|
echo "XDG_RUNTIME_DIR=/run/user/$uid"
|
|
echo "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus"
|
|
} >> "$GITHUB_ENV"
|
|
|
|
- name: Onboard with the background service
|
|
env:
|
|
PAPERCLIPAI_VERSION: ${{ inputs.paperclip_version }}
|
|
DATA_DIR: ${{ runner.temp }}/service-smoke-data
|
|
SMOKE_CLEANUP: "false"
|
|
run: ./scripts/service-onboard-smoke.sh
|
|
|
|
- name: Capture service diagnostics
|
|
if: always()
|
|
run: |
|
|
{
|
|
systemctl --user --no-pager status paperclipai.service || true
|
|
journalctl --user -u paperclipai.service --no-pager || true
|
|
} > "$RUNNER_TEMP/paperclipai-service.log" 2>&1
|
|
|
|
- name: Upload service diagnostics
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: ${{ inputs.artifact_name }}-service
|
|
path: ${{ runner.temp }}/paperclipai-service.log
|
|
retention-days: 14
|
|
|
|
smoke:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
|
|
# Fixed here rather than read back out of the harness, so the `always()`
|
|
# diagnostics steps below still know the container's name when the launch
|
|
# step is the thing that failed. Reading it back was why a failing smoke
|
|
# uploaded no Docker logs at all.
|
|
env:
|
|
SMOKE_CONTAINER_NAME: release-smoke-onboard
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v6
|
|
with:
|
|
version: 9.15.4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v7
|
|
with:
|
|
node-version: 24
|
|
cache: pnpm
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --no-frozen-lockfile
|
|
|
|
- name: Verify runner Chrome
|
|
# Release smoke also runs headless on GitHub's Ubuntu image, so use the
|
|
# runner's preinstalled Chrome instead of a Playwright browser download.
|
|
run: google-chrome --version
|
|
|
|
- name: Launch Docker smoke harness
|
|
run: |
|
|
HOST_PORT="${{ inputs.host_port }}" \
|
|
DATA_DIR="$RUNNER_TEMP/release-smoke-data" \
|
|
PAPERCLIPAI_VERSION="${{ inputs.paperclip_version }}" \
|
|
SMOKE_READY_TIMEOUT_SECONDS=420 \
|
|
SMOKE_DETACH=true \
|
|
SMOKE_METADATA_FILE="${{ runner.temp }}/release-smoke.env" \
|
|
SMOKE_LOG_FILE="${{ runner.temp }}/docker-onboard-smoke.log" \
|
|
./scripts/docker-onboard-smoke.sh
|
|
set -a
|
|
source "${{ runner.temp }}/release-smoke.env"
|
|
set +a
|
|
{
|
|
echo "SMOKE_BASE_URL=$SMOKE_BASE_URL"
|
|
echo "SMOKE_ADMIN_EMAIL=$SMOKE_ADMIN_EMAIL"
|
|
echo "SMOKE_ADMIN_PASSWORD=$SMOKE_ADMIN_PASSWORD"
|
|
echo "SMOKE_DATA_DIR=$SMOKE_DATA_DIR"
|
|
echo "SMOKE_IMAGE_NAME=$SMOKE_IMAGE_NAME"
|
|
echo "SMOKE_PAPERCLIPAI_VERSION=$SMOKE_PAPERCLIPAI_VERSION"
|
|
} >> "$GITHUB_ENV"
|
|
|
|
- name: Run release smoke Playwright suite
|
|
env:
|
|
PAPERCLIP_RELEASE_SMOKE_BASE_URL: ${{ env.SMOKE_BASE_URL }}
|
|
PAPERCLIP_RELEASE_SMOKE_EMAIL: ${{ env.SMOKE_ADMIN_EMAIL }}
|
|
PAPERCLIP_RELEASE_SMOKE_PASSWORD: ${{ env.SMOKE_ADMIN_PASSWORD }}
|
|
PAPERCLIP_PLAYWRIGHT_CHANNEL: "chrome"
|
|
run: pnpm run test:release-smoke
|
|
|
|
- name: Capture Docker logs
|
|
if: always()
|
|
run: |
|
|
log_file="${{ runner.temp }}/docker-onboard-smoke.log"
|
|
# A live container has the fuller story, so prefer it. When the
|
|
# harness already tore the container down it wrote this file on its
|
|
# way out, and that copy is kept rather than clobbered.
|
|
if docker inspect "$SMOKE_CONTAINER_NAME" >/dev/null 2>&1; then
|
|
docker logs "$SMOKE_CONTAINER_NAME" >"$log_file" 2>&1 || true
|
|
fi
|
|
# Never leave the upload with nothing to say. An absent log reads as
|
|
# a missing artifact; a file saying the container was gone reads as
|
|
# the diagnosis it is.
|
|
if [[ ! -s "$log_file" ]]; then
|
|
echo "No Docker logs captured: container '$SMOKE_CONTAINER_NAME' left no log dump and is no longer present." >"$log_file"
|
|
fi
|
|
echo "Captured $(wc -l <"$log_file") log lines to $log_file"
|
|
|
|
- name: Upload diagnostics
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: ${{ inputs.artifact_name }}
|
|
path: |
|
|
${{ runner.temp }}/docker-onboard-smoke.log
|
|
${{ runner.temp }}/release-smoke.env
|
|
tests/release-smoke/playwright-report/
|
|
tests/release-smoke/test-results/
|
|
# The capture step above guarantees the log file, so an empty upload
|
|
# means the diagnostics wiring itself broke — which is worth failing
|
|
# over rather than burying in a warning nobody reads.
|
|
if-no-files-found: error
|
|
retention-days: 14
|
|
|
|
- name: Stop Docker smoke container
|
|
if: always()
|
|
run: docker rm -f "$SMOKE_CONTAINER_NAME" >/dev/null 2>&1 || true
|