ci: make a failed deploy hook say why nothing was deployed
The failure
Pipeline #33046 (production) failed in deploy with its entire diagnosis being:
curl: (22) The requested URL returned error: 404
What is actually wrong
All three build jobs succeeded and pushed :production images. Only the hook POST failed.
- The same job, script, runner and variable name succeeds on
beta(job 43730). -
back-end/flight's production deploy answers204from the same runner.
So neither this CI file nor the production Portainer is broken. The production-scoped
SERVICE_HOOK holds a webhook token Portainer does not have — that is Portainer's standard
404, whose body reads Unable to find a webhook with this token. curl -f prints only the
status line and throws that body away, which is why the job said nothing useful.
The most likely cause: the production-safrat-assistant stack (docker-compose-production.yml)
has never been created in the production Portainer, so no webhook for it exists yet and the
variable holds a stale or copied-from-beta value.
What this MR changes
The real fix is infra-side and cannot be committed: create the stack, then put its webhook
into the production-scoped SERVICE_HOOK. This MR fixes the part that lives in the repo —
the job that could not tell you any of the above.
- Inspect the status code instead of
curl -f, and print Portainer's response body. Non-2xx still fails the job, exactly as before. - Log the target URL with the token segment redacted, so the trace shows which Portainer and which webhook endpoint the environment points at. A value copied from the other environment used to look identical to a dead one.
- Spell out the three causes of a 404 and the fix, in the trace, at the moment of failure.
- Retry only connection failures and 5xx (3 attempts). A 4xx is a configuration answer — re-POSTing a dead token is what made "just retry the deploy job" a waste of time.
- Say plainly that a 2xx is not proof of rollout, with the verify command.
- Document in the header that
SERVICE_HOOKis per-environment and that the two values are not interchangeable.
What the failing job would print after this MR
POST https://<portainer-host>/api/stacks/webhooks/<redacted> (environment: production)
HTTP 404
Portainer response: {"message":"Unable to find a webhook with this token","details":"Object not found inside the database"}
NOTHING WAS DEPLOYED - Portainer does not know this webhook.
The 'production'-scoped SERVICE_HOOK holds a token that is not registered. Usual causes:
1. The stack does not exist yet in that Portainer - a webhook is created WITH the stack.
Deploy docker-compose-production.yml as stack 'production-safrat-assistant' first.
2. The stack was deleted and recreated - the webhook UUID changed and the old one 404s forever.
3. The value belongs to the OTHER environment's Portainer, or it is a service webhook
(/api/webhooks/<uuid>) pasted where a stack webhook (/api/stacks/webhooks/<uuid>) is expected.
Fix: copy the webhook from the stack's page in Portainer into the 'production'-scoped variable.
Verification
Ran the script against a fake Portainer under busybox ash (the deploy image's shell):
404, 204, 5xx-retry, connection-refused, unset and non-URL values each produce the right
message and exit code. The config passes the GitLab CI lint API (valid: true).
Note this MR alone does not make production deploy — it makes the next failure legible.
The stack + webhook still have to be created before production goes green.