---
name: ci-release
description: >
  Release a Pysae application: bump semver, trigger release pipeline on main, wait for tag pipeline,
  deploy to prod via /ci-deploy, then monitor rollout health on Kubernetes and Datadog.
  Use when the user says /ci-release, /release, 'release', 'fais une release',
  'nouvelle version', 'bump version', 'release en prod', or wants to cut a new version.
argument-hint: "<optional: app name> <optional: major|minor|patch (default: auto from changelogs)> <optional: version override e.g. v1.2.3>"
allowed-tools:
  - Read
  - Glob
  - Grep
  - Bash
  - Skill
  - AskUserQuestion
  - mcp__kubernetes__kubectl_get
  - mcp__kubernetes__kubectl_describe
  - mcp__datadog__get_logs
  - mcp__datadog__list_monitors
---

Release a Pysae application: determine the next semver version, trigger a release pipeline on main, wait for the tag pipeline, deploy to production, and monitor the rollout.

## Required tools

- `glab`
- `kubectl`
- `datadog-mcp`

Run `pysae-ai-tools tools require <tools>` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Mode detection

```bash
CTX=$(pysae-ai-tools internal detect-context)
IS_CI=$(echo "$CTX" | jq -r '.is_ci')
PROJECT_ID=$(echo "$CTX" | jq -r '.project_id // empty')
PROJECT_PATH=$(echo "$CTX" | jq -r '.project_path // empty')
```

CI mode: never use `AskUserQuestion`, skip confirmations, fail with exit code 1 on missing args.

## Step 1 — Target repository

Resolve the target application using [../references/pysae-projects.md](../references/pysae-projects.md) (section "Application repositories"). **Default**: `pysae/api`.

If targeting a different repo than the current directory, resolve `PROJECT_ID` via `glab api "projects/<url-encoded-path>"`.

## Step 2 — Check release support

```bash
CI_YAML=$(glab api "projects/${PROJECT_ID}/repository/files/.gitlab-ci.yml/raw?ref=main" 2>/dev/null)
```

Check if the YAML includes `release.auto.yml` (from `pysae/infra/gitlab-templates`). If not found, stop — the project does not support automated releases.

## Step 3 — Determine the next version

```bash
VERSION_JSON=$(pysae-ai-tools ci release next-version --project-id ${PROJECT_ID})
```

The script returns: `new_version`, `bump`, `latest_tag`, `version_patch`, `version_minor`, `version_major`. Override with `--bump <type>` or `--version v1.2.3` from `$ARGUMENTS`.

**Local mode only — display the changelog before asking.** List and read all changelog entries on `main` so the user can judge the bump type:

```bash
glab api "projects/${PROJECT_ID}/repository/tree?path=changelogs&ref=main" \
  | jq -r '.[] | select(.name | endswith(".md")) | .path'
# For each file returned:
glab api "projects/${PROJECT_ID}/repository/files/<url-encoded-path>/raw?ref=main"
```

Display the aggregated changelog content to the user in French, grouped by type (feat / fix / refactor / tech / docs / chore / perf / BREAKING), then show the release summary and prompt with `AskUserQuestion`. Use `version_patch`, `version_minor`, `version_major` from the script output. Exclude the option that matches the auto-detected bump:

> Release de `<app>` : `<latest_tag>` → `<new_version>` (`<bump>`)
>
> - **Oui** — confirmer `<new_version>`
> - **Force patch** — `<version_patch>` *(only if bump ≠ patch)*
> - **Force minor** — `<version_minor>` *(only if bump ≠ minor)*
> - **Force major** — `<version_major>` *(only if bump ≠ major)*
> - **Annuler**

If the user picks a force option, use that version directly (no need to re-run the script). Stop if the user cancels.

## Step 4 — Trigger and wait for the release pipeline

1. Create the pipeline:
   ```bash
   pysae-ai-tools ci run create --project-id ${PROJECT_ID} --ref main --var RELEASE_VERSION=${NEW_VERSION}
   ```
   Extract `RELEASE_PIPELINE_ID` from output. Verify the `release` job exists in the pipeline jobs.

2. Wait for it to succeed (run in background in local mode):
   ```bash
   pysae-ai-tools ci run wait --project-id ${PROJECT_ID} --pipeline-id ${RELEASE_PIPELINE_ID}
   ```
   On failure → `/ci-debug`.

3. Verify the tag was created:
   ```bash
   glab api "projects/${PROJECT_ID}/repository/tags/${NEW_VERSION}" | jq -r '.name'
   ```

## Step 5 — Wait for the tag pipeline

The tag creation triggers a separate pipeline. Find it:
```bash
TAG_PIPELINE=$(glab api "projects/${PROJECT_ID}/pipelines?ref=${NEW_VERSION}&per_page=1" | jq -r '.[0]')
TAG_PIPELINE_ID=$(echo "$TAG_PIPELINE" | jq -r '.id')
TAG_PIPELINE_URL=$(echo "$TAG_PIPELINE" | jq -r '.web_url')
```
If no tag pipeline after 30s, report error and stop.

**Display the tag pipeline link to the user** before monitoring.

Wait for the tag pipeline (run in background in local mode):
```bash
pysae-ai-tools ci run wait --project-id ${PROJECT_ID} --pipeline-id ${TAG_PIPELINE_ID}
```

The `wait` command returns `status=manual` as a successful terminal state — this is expected and means all automatic jobs (build, release assets) succeeded and a manual `deploy` job is ready. Do **not** keep waiting in that case: move on to Step 6 where `/ci-deploy` will trigger the manual job. Only treat `failed` / `canceled` as errors → `/ci-debug`.

## Step 6 — Deploy to production and monitor rollout

Delegate to `/ci-deploy` with arguments: `prod <NEW_VERSION>` (+ app name if not default). It handles confirmation, job execution via `/ci-run`, and pipeline monitoring.

After `/ci-deploy` completes, monitor Kubernetes rollout and Datadog errors:

**Kubernetes**: list **all** deployments for the app using `K8S_DEPLOYMENT` from [../references/pysae-projects.md](../references/pysae-projects.md). Some apps have multiple deployments (e.g. `pysae/api` has flavors: `api`, `api-fast`, `api-ndp`, `api-gtfsrt`, `api-evt`, `api-stats`, `api-simu`, `api-docs`):

```bash
# List all deployments matching the app pattern in the prod namespace
kubectl get deployments -n prod -l app.kubernetes.io/name=<K8S_DEPLOYMENT> --no-headers
# Or by name prefix:
kubectl get deployments -n prod --no-headers | grep "^prod-<deployment-prefix>"
```

For each deployment found:
- `kubectl rollout status deployment/<name> -n prod --timeout=10s`
- Check pod health and image tag
- Alert on CrashLoopBackOff/OOMKilled

**All deployments must be healthy** before declaring rollout complete.

**Datadog**: use `mcp__datadog__get_logs` to check for error spikes in the last 15 minutes. On errors: propose rollback.

**End conditions**: all deployments ready + no errors for 5 min → success. Critical errors → alert + suggest rollback. User says stop → stop.

**Final report**:
> **Release `<NEW_VERSION>` — `<app>`**
> - Pipeline release : [link] — `success`
> - Pipeline tag : [link] — `success`
> - Deploy prod : [link] — `success`
> - Rollout : complete — X/Y deployments ready (list each)
> - Erreurs post-deploy : aucune

## Rules

- **Confirmation required** for version (local) and prod deploy (via `/ci-deploy`) — skipped in CI
- **Default bump**: auto from changelogs, fallback patch
- **Default app**: `pysae/api`
- **Stop on pipeline failure** → `/ci-debug`
- **Alert immediately on rollout errors**
- **French** for communication, English for commands. Apply [french-writing-rules.md](../references/french-writing-rules.md).
- **Delegate deploy** to `/ci-deploy` — never duplicate deployment logic

$ARGUMENTS
