Skip to content

Commit 6d555f2

Browse files
authored
Replace curl+bash API layer with zad-cli (#41)
* refactor: replace curl+bash API layer with zad-cli Replace all ZAD API interactions (curl_with_retry, poll_task, build_poll_url, payload building) with zad-cli calls. The CLI handles retry logic, task polling, and error handling identically. - deploy: ~200 lines of curl/jq/polling replaced by single CLI call - cleanup: ~80 lines of curl/polling replaced by single CLI call - scheduled-cleanup: same ZAD delete logic replaced by CLI call - Remove scripts/zad-common.sh (124 lines, now redundant) GitHub-specific logic (bot detection, PR comments, QR codes, environment/deployment/container cleanup) unchanged. Net reduction: ~310 lines of duplicated bash. * fix: address PR review - error detail, temp files, validation, install - Structured error reporting: parse CLI JSON status_code for specific ::error:: annotations (401/403/404/5xx), matching original messages - Add scripts/zad-error.sh helper for deploy action error reporting - Remove zad_stderr.txt temp file usage: CLI JSON errors go to stdout in --output json mode, so stderr redirect was reading the wrong stream - Restore domain_format subdomain-requires-subdomain validation in deploy action (not covered by CLI validation) - Use uv for installation (faster, consistent with project tooling) - Install from main without version pin (both repos under same team) * refactor: unify shared helpers, fix all review issues - Consolidate zad-error.sh into zad-common.sh with install_zad_cli, report_zad_error, and zad_delete_deployment functions - All three actions now use the same shared functions (DRY) - cleanup and scheduled-cleanup use zad_delete_deployment instead of duplicated inline error parsing - Replace curl|sh uv install with pip install (available on all GitHub runners, no external script execution) - Remove zad-error.sh (merged into zad-common.sh) * fix: suppress shellcheck SC2034 for variables used by callers * fix: pin zad-cli to version tag and use uv for installation Install from a specific version tag (v0.1.1) instead of unpinned main to prevent breaking changes from affecting all workflows. Switch from pip to uv (faster, consistent with project tooling). * fix: restore input validation and harden CLI error handling - Restore input validation (project-id, deployment-name, component names, numeric inputs, domain inputs) before logging to prevent injection. Extracted validate_input and validate_integer helpers to zad-common.sh for reuse across all three actions. - Handle non-JSON CLI output in report_zad_error (crashes, missing binary, Python tracebacks no longer produce misleading messages). - Check install_zad_cli exit code and verify zad is in PATH. - Reset DELETE_RESULT/DELETE_REASON at start of zad_delete_deployment to prevent stale values when called in a loop. - Use ::warning:: (not ::error::) for cleanup delete failures to match the original best-effort behavior. * fix: add setup-uv, fix validation exits, harden CLI install - Add astral-sh/setup-uv@v6 step before zad-cli install (uv is not pre-installed on GitHub runners) - Add $HOME/.local/bin to GITHUB_PATH so zad is available across steps - Change validate_input/validate_integer from return 1 to exit 1 (without set -e, return 1 was silently ignored) - Add missing validate_input for project-id in scheduled-cleanup - Improve error message for CLI failures with no HTTP status code - Update CHANGELOG.md with full PR scope * fix: correct uv tool bin path and not_found cleanup counting Use `uv tool bin` instead of broken `uv tool dir/../bin` fallback, and make PATH export consistent with whichever branch fires. Count not_found deployments as successfully cleaned in scheduled-cleanup since a missing deployment is already clean.
1 parent 68688a1 commit 6d555f2

5 files changed

Lines changed: 303 additions & 400 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Changed
11+
- **all actions**: Replace curl+bash API layer with [zad-cli](https://github.com/RijksICTGilde/zad-cli) (pinned to v0.1.1)
12+
- **deploy**: ~200 lines of curl/jq/polling replaced by single `zad deployment create` call
13+
- **cleanup**: ~80 lines of curl/polling replaced by single `zad deployment delete` call
14+
- **scheduled-cleanup**: same inline curl/polling replaced by shared `zad_delete_deployment` helper
15+
- Retry logic, task polling, and error handling now delegated to the CLI
16+
- Net reduction: ~310 lines of duplicated bash
17+
- **scripts/zad-common.sh**: Rewritten — `curl_with_retry`, `poll_task`, and `build_poll_url` replaced by `install_zad_cli`, `validate_input`, `validate_integer`, `report_zad_error`, and `zad_delete_deployment`
18+
- **all actions**: ZAD configuration now uses `ZAD_*` env vars (`ZAD_API_URL`, `ZAD_PROJECT_ID`, `ZAD_MAX_RETRIES`, `ZAD_RETRY_DELAY`, `ZAD_TASK_TIMEOUT`, `ZAD_TASK_POLL_INTERVAL`) consumed directly by the CLI
19+
20+
### Added
21+
- **all actions**: `astral-sh/setup-uv` step to ensure `uv` is available on GitHub runners
22+
- **all actions**: `$HOME/.local/bin` added to `GITHUB_PATH` after install so `zad` is available across steps
23+
24+
### Fixed
25+
- **all actions**: `validate_input` and `validate_integer` now `exit 1` instead of `return 1` (validation failures were silently ignored without `set -e`)
26+
- **scheduled-cleanup**: Add missing `validate_input "project-id"` check (was present in deploy and cleanup but missing here)
27+
- **all actions**: Improve error message when CLI fails with no HTTP status code
28+
1029
## [3.2.0] - 2026-03-20
1130

1231
### Added

cleanup/action.yml

Lines changed: 33 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -135,90 +135,54 @@ runs:
135135
done
136136
echo "skipped=false" >> "$GITHUB_OUTPUT"
137137
138+
- name: Setup uv
139+
if: steps.bot-check.outputs.skipped != 'true'
140+
uses: astral-sh/setup-uv@v6
141+
142+
- name: Install zad-cli
143+
if: steps.bot-check.outputs.skipped != 'true'
144+
shell: bash
145+
run: |
146+
# shellcheck source=../scripts/zad-common.sh
147+
source "$GITHUB_ACTION_PATH/../scripts/zad-common.sh"
148+
install_zad_cli
149+
138150
- name: Delete ZAD Deployment
139151
id: delete-zad
140152
if: steps.bot-check.outputs.skipped != 'true'
141153
shell: bash
142154
env:
143155
ZAD_API_KEY: ${{ inputs.api-key }}
144-
PROJECT_ID: ${{ inputs.project-id }}
156+
ZAD_API_URL: ${{ inputs.api-base-url }}
157+
ZAD_PROJECT_ID: ${{ inputs.project-id }}
158+
ZAD_MAX_RETRIES: ${{ inputs.max-retries }}
159+
ZAD_RETRY_DELAY: ${{ inputs.retry-delay }}
160+
ZAD_TASK_TIMEOUT: ${{ inputs.task-timeout }}
161+
ZAD_TASK_POLL_INTERVAL: ${{ inputs.task-poll-interval }}
145162
DEPLOYMENT_NAME: ${{ inputs.deployment-name }}
146-
API_BASE_URL: ${{ inputs.api-base-url }}
147-
MAX_RETRIES: ${{ inputs.max-retries }}
148-
RETRY_DELAY: ${{ inputs.retry-delay }}
149-
TASK_TIMEOUT: ${{ inputs.task-timeout }}
150-
TASK_POLL_INTERVAL: ${{ inputs.task-poll-interval }}
163+
NO_COLOR: '1'
151164
run: |
152-
# Validate inputs FIRST (before logging)
153-
# Allow alphanumeric, hyphens, underscores, and dots
154-
if ! echo "$PROJECT_ID" | grep -qE '^[a-zA-Z0-9._-]+$'; then
155-
echo "Error: project-id contains invalid characters (allowed: a-z, A-Z, 0-9, ., _, -)"
156-
exit 1
157-
fi
158-
if ! echo "$DEPLOYMENT_NAME" | grep -qE '^[a-zA-Z0-9._-]+$'; then
159-
echo "Error: deployment-name contains invalid characters (allowed: a-z, A-Z, 0-9, ., _, -)"
160-
exit 1
161-
fi
162-
if ! echo "$MAX_RETRIES" | grep -qE '^[0-9]+$'; then
163-
echo "Error: max-retries must be a non-negative integer"
164-
exit 1
165-
fi
166-
if ! echo "$RETRY_DELAY" | grep -qE '^[0-9]+$'; then
167-
echo "Error: retry-delay must be a non-negative integer"
168-
exit 1
169-
fi
170-
if ! echo "$TASK_TIMEOUT" | grep -qE '^[0-9]+$'; then
171-
echo "Error: task-timeout must be a non-negative integer"
172-
exit 1
173-
fi
174-
if ! echo "$TASK_POLL_INTERVAL" | grep -qE '^[0-9]+$'; then
175-
echo "Error: task-poll-interval must be a non-negative integer"
176-
exit 1
177-
fi
178-
179-
# Now safe to log
180-
echo "Deleting ZAD deployment: $DEPLOYMENT_NAME from project: $PROJECT_ID"
181-
182-
# Load shared helpers (curl_with_retry, poll_task, build_poll_url)
183165
# shellcheck source=../scripts/zad-common.sh
184166
source "$GITHUB_ACTION_PATH/../scripts/zad-common.sh"
185167
186-
if curl_with_retry "$API_BASE_URL/v2/projects/$PROJECT_ID/$DEPLOYMENT_NAME" \
187-
-X DELETE \
188-
-H "X-API-Key: $ZAD_API_KEY"; then
168+
# Validate inputs FIRST (before logging, to prevent injection)
169+
validate_input "project-id" "$ZAD_PROJECT_ID"
170+
validate_input "deployment-name" "$DEPLOYMENT_NAME"
171+
validate_integer "max-retries" "$ZAD_MAX_RETRIES"
172+
validate_integer "retry-delay" "$ZAD_RETRY_DELAY"
173+
validate_integer "task-timeout" "$ZAD_TASK_TIMEOUT"
174+
validate_integer "task-poll-interval" "$ZAD_TASK_POLL_INTERVAL"
189175
190-
TASK_ID=$(echo "$FINAL_BODY" | jq -r '.task_id' 2>/dev/null)
191-
POLL_URL=$(echo "$FINAL_BODY" | jq -r '.poll_url' 2>/dev/null)
192-
echo "Delete task accepted (ID: $TASK_ID), polling for completion..."
176+
echo "Deleting ZAD deployment: $DEPLOYMENT_NAME from project: $ZAD_PROJECT_ID"
193177
194-
FULL_POLL_URL=$(build_poll_url "$POLL_URL")
178+
zad_delete_deployment "$DEPLOYMENT_NAME"
195179
196-
if poll_task "$FULL_POLL_URL"; then
197-
echo "ZAD deployment deleted successfully"
198-
echo "deleted=true" >> "$GITHUB_OUTPUT"
199-
else
200-
echo "::error::ZAD deployment delete task did not complete successfully"
201-
echo "deleted=false" >> "$GITHUB_OUTPUT"
202-
fi
203-
else
204-
if [ "$FINAL_HTTP_CODE" -eq 404 ]; then
205-
echo "ZAD deployment not found (already deleted?)"
206-
echo "deleted=false" >> "$GITHUB_OUTPUT"
207-
elif [ "$FINAL_HTTP_CODE" -eq 000 ]; then
208-
echo "::warning::Unable to connect to ZAD API - network issue or API unavailable"
209-
echo "deleted=false" >> "$GITHUB_OUTPUT"
210-
elif [ "$FINAL_HTTP_CODE" -eq 401 ]; then
211-
echo "::warning::Authentication failed (HTTP 401) - verify ZAD_API_KEY is correct"
212-
echo "deleted=false" >> "$GITHUB_OUTPUT"
213-
elif [ "$FINAL_HTTP_CODE" -eq 403 ]; then
214-
echo "::warning::Access denied (HTTP 403) - API key may lack permission for project '$PROJECT_ID'"
215-
echo "deleted=false" >> "$GITHUB_OUTPUT"
216-
else
217-
echo "::warning::Failed to delete ZAD deployment (HTTP $FINAL_HTTP_CODE)"
218-
echo "$FINAL_BODY"
219-
echo "deleted=false" >> "$GITHUB_OUTPUT"
220-
fi
180+
if [ "$DELETE_RESULT" = "true" ]; then
181+
echo "ZAD deployment deleted successfully"
182+
elif [ "$DELETE_REASON" = "not_found" ]; then
183+
echo "ZAD deployment not found (already deleted?)"
221184
fi
185+
echo "deleted=$DELETE_RESULT" >> "$GITHUB_OUTPUT"
222186
223187
- name: Delete GitHub Deployments
224188
id: delete-github-deployments

0 commit comments

Comments
 (0)