Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [4.0.6] - 2026-06-19

### Changed
- Bump zad-cli from v0.6.0 to v0.8.0 (admin orphan-report/orphan-confirm commands, and a new structured error diagnosis layer with source labels, next-step suggestions and CI exit codes 1/2/3)
- Update `report_zad_error` to read zad-cli's new diagnosis JSON (`headline`, `summary`, `next_steps`) so error annotations surface the cause and remediation; falls back to the old flat `error` field for version skew. Network/unknown failures (HTTP status 0) now keep their message instead of dropping it.

## [4.0.5] - 2026-05-19

### Changed
Expand Down
33 changes: 25 additions & 8 deletions scripts/zad-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# Install zad-cli if not already available.
# Pin to a specific version tag to prevent breaking changes.
ZAD_CLI_VERSION="v0.6.0"
ZAD_CLI_VERSION="v0.8.0"

install_zad_cli() {
if command -v zad >/dev/null 2>&1; then
Expand Down Expand Up @@ -61,8 +61,11 @@ validate_integer() {
#
# Usage: report_zad_error <operation> <cli_stdout> <project-id>
#
# The CLI outputs JSON errors to stdout in --output json mode:
# {"error": "HTTP 401: ...", "status_code": 401}
# zad-cli >= v0.7.0 outputs a structured diagnosis to stdout in --output json mode:
# {"fault": "Auth", "headline": "Authentication failed (HTTP 401).",
# "summary": "...", "next_steps": ["..."], "status_code": 401}
# Older CLIs used a flat {"error": "HTTP 401: ...", "status_code": 401}; we fall
# back to that shape so a version skew never swallows the message.
report_zad_error() {
local operation="$1"
local cli_stdout="$2"
Expand All @@ -75,14 +78,16 @@ report_zad_error() {
return
fi

local status_code error_msg
local status_code headline summary
status_code=$(echo "$cli_stdout" | jq -r '.status_code // 0' 2>/dev/null || echo "0")
error_msg=$(echo "$cli_stdout" | jq -r '.error // empty' 2>/dev/null || echo "")
# Prefer the new diagnosis headline; fall back to the old flat .error field.
headline=$(echo "$cli_stdout" | jq -r '.headline // .error // empty' 2>/dev/null || echo "")
summary=$(echo "$cli_stdout" | jq -r '.summary // empty' 2>/dev/null || echo "")

case "$status_code" in
0)
if [ -n "$error_msg" ]; then
echo "::error::${operation} failed: $error_msg"
if [ -n "$headline" ]; then
echo "::error::${operation} failed: $headline"
else
echo "::error::${operation} failed with no HTTP status code"
echo "::error::This could be a network issue, timeout, or CLI error"
Expand All @@ -104,10 +109,22 @@ report_zad_error() {
if [ "$status_code" -ge 500 ] 2>/dev/null; then
echo "::error::${operation} failed: ZAD API server error (HTTP $status_code) after retries"
else
echo "::error::${operation} failed (HTTP $status_code): $error_msg"
echo "::error::${operation} failed (HTTP $status_code): ${headline:-error}"
fi
;;
esac

# Surface the backend's own summary and remediation, when present.
if [ -n "$summary" ] && [ "$summary" != "$headline" ]; then
echo "::error::Details: $summary"
fi
local steps
steps=$(echo "$cli_stdout" | jq -r '.next_steps[]? // empty' 2>/dev/null || echo "")
if [ -n "$steps" ]; then
while IFS= read -r step; do
[ -n "$step" ] && echo "::error::Next step: $step"
done <<< "$steps"
fi
}

# Delete a ZAD deployment via CLI, handling not-found gracefully.
Expand Down