Files
qqq-cli/scripts/verify-binary.sh
T
james.maesandClaude Fable 5.1 05846459dd scripts: verify-binary.sh and .ps1, the binary smoke for CI lanes and releases
Version with "binary with ui", completion for four shells, qqq ui
--check naming the build, and with a server: login, doctor, whoami, a
query and a process run, in a temporary profile (file keyring, or the OS
keyring removed again). Run here on darwin-arm64 (both keyrings), in
Debian amd64, and the .ps1 under PowerShell 7 in a Linux container, all
against the sample server; never on Windows. The proposed lane YAML now
calls them and still validates; ci-lanes.md says Windows x64 and macOS
x64 stay unverified until the lanes run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 19:21:50 -05:00

100 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Copyright 2026 QRun.IO, Inc.
# Licensed under the Apache License, Version 2.0 (see LICENSE).
#
# Smoke test of one qqq binary (or any qqq on the PATH): version and build, completion, the terminal
# UI's check, and with --server the commands a user runs first: login, whoami, a query and a process
# run. CI lanes run it on the binary they built; run it by hand after a release on what was downloaded.
#
# scripts/verify-binary.sh dist/qqq-darwin-arm64
# scripts/verify-binary.sh dist/qqq-linux-x64 --server http://localhost:8077
# scripts/verify-binary.sh qqq --server https://qqq.example.com --profile prod --keyring os
#
# Options:
# --server URL also sign in and run whoami, query and process run against this server
# (MOCK and anonymous servers sign in without a browser; others need --profile of
# an existing sign-in)
# --profile NAME use this existing profile instead of a temporary one
# --keyring os keep the temporary sign-in in the OS keyring (removed again at the end) instead of
# a file in a temporary config directory
# --cli-only the binary is a CLI-only build: do not expect "with ui" or run ui --check
# QQQ_VERIFY_TABLE (person), QQQ_VERIFY_PROCESS (sleepInteractive), QQQ_VERIFY_VALUES (sleepMillis=500)
# what to query and run; the defaults fit the QQQ sample app
# Exit 0 when every step passed; the failing steps are listed otherwise.
set -uo pipefail
bin="${1:?usage: verify-binary.sh <qqq binary> [--server URL] [--profile NAME] [--keyring os] [--cli-only]}"
shift
server=""; profile=""; keyring="file"; ui=1
while [[ $# -gt 0 ]]; do
case "$1" in
--server) server="$2"; shift 2 ;;
--profile) profile="$2"; shift 2 ;;
--keyring) keyring="$2"; shift 2 ;;
--cli-only) ui=0; shift ;;
*) echo "verify-binary: unknown option $1" >&2; exit 2 ;;
esac
done
table="${QQQ_VERIFY_TABLE:-person}"
process_name="${QQQ_VERIFY_PROCESS:-sleepInteractive}"
values="${QQQ_VERIFY_VALUES:-sleepMillis=500}"
if [[ -z "$profile" ]]; then
work="$(mktemp -d)"
export QQQ_CONFIG_DIR="$work/config" QQQ_CACHE_DIR="$work/cache"
[[ "$keyring" == file ]] && export QQQ_KEYRING=file
profile="verify-$$"
temporary=1
else
temporary=0
fi
export QQQ_OUTPUT=json
failed=()
pass() { printf 'ok %s\n' "$1"; }
fail() { printf 'FAIL %s: %s\n' "$1" "$2"; failed+=("$1"); }
# step NAME EXPECTED-REGEX COMMAND...: runs the command, checks exit 0 and that the output matches
step() {
local name="$1" want="$2"; shift 2
local out
if out="$("$@" 2>&1)" && grep -Eq -- "$want" <<<"$out"; then pass "$name"; else fail "$name" "$(head -c 400 <<<"$out")"; fi
}
step "version" '^qqq [0-9]+\.[0-9]+\.[0-9]+' "$bin" --version
if [[ $ui == 1 ]]; then
step "version says with ui" 'binary with ui' "$bin" --version
else
pass "version (CLI-only build, ui not expected)"
fi
step "completion candidates" '^table$' "$bin" __complete -- ta
for shell in bash zsh fish pwsh; do step "completion $shell" 'qqq' "$bin" completion "$shell"; done
if [[ $ui == 1 ]]; then
step "ui --check names the build" 'binary with ui.*runtime \(embedded\)' "$bin" ui --check
else
# shellcheck disable=SC2016 # $0 is expanded by the inner bash
step "ui says how to get the UI" 'not part of this installation' bash -c '"$0" ui; true' "$bin"
fi
if [[ -n "$server" ]]; then
if [[ $temporary == 1 ]]; then
step "login (session)" 'Signed in' "$bin" login --server "$server" --profile "$profile"
fi
step "doctor build line" '"build": "qqq ' "$bin" --profile "$profile" doctor
step "whoami" '"apiVersion"' "$bin" --profile "$profile" whoami
step "table query $table" '"values"' "$bin" --profile "$profile" table query "$table" -l 2
args=(); IFS=',' read -ra pairs <<<"$values"; for p in "${pairs[@]}"; do args+=(-v "$p"); done
step "process run $process_name" '"type": "COMPLETE"' "$bin" --profile "$profile" process run "$process_name" "${args[@]}"
if [[ $temporary == 1 ]]; then
step "logout" 'Signed out' "$bin" --profile "$profile" logout
"$bin" config profile remove "$profile" >/dev/null 2>&1 || true
fi
fi
[[ $temporary == 1 ]] && rm -rf "$work"
if [[ ${#failed[@]} -gt 0 ]]; then
echo "verify-binary: ${#failed[@]} failed: ${failed[*]}"
exit 1
fi
echo "verify-binary: ok"