name: knooing Change
description: Legt einen Change in knooing an (mode open) oder meldet das Ergebnis eines Rollouts (mode status).
author: knooing
inputs:
  mode:
    description: "open legt den Change an, status meldet das Ergebnis."
    required: true
  api-url:
    description: Basis-URL der knooing-API.
    required: false
    default: https://api.knooing.info
  api-key:
    description: "API-Schlüssel mit Scope changes:write. Nur aus einem GitHub-Secret übergeben (secrets.KNOOING_API_KEY)."
    required: true
  service-id:
    description: "ID des Services (nur mode open)."
    required: false
  title:
    description: "Titel des Changes (nur mode open)."
    required: false
    default: Deployment ${{ github.repository }} ${{ github.sha }}
  description:
    description: "Beschreibung (nur mode open)."
    required: false
    default: Automatisches Deployment aus ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
  impact:
    description: "Auswirkung 1 bis 5 (nur mode open)."
    required: false
    default: "2"
  urgency:
    description: "Dringlichkeit 1 bis 5 (nur mode open)."
    required: false
    default: "2"
  change-class:
    description: "standard, normal oder emergency (nur mode open)."
    required: false
    default: standard
  rollback-plan:
    description: "Rückfallplan (nur mode open, optional)."
    required: false
    default: ""
  external-key:
    description: "Schlüssel gegen Doppelanlage (nur mode open). Standard ist die Workflow-Lauf-ID."
    required: false
    default: github-${{ github.repository }}-${{ github.run_id }}
  change-id:
    description: "Change-Datensatz-ID aus dem Open-Schritt (nur mode status)."
    required: false
  outcome:
    description: "successful, partial, failed oder rolled_back (nur mode status)."
    required: false
    default: successful
  note:
    description: "Bemerkung zum Ergebnis (nur mode status, optional)."
    required: false
    default: ""
outputs:
  change-id:
    description: "ID des angelegten Change-Datensatzes (mode open). Leer, wenn der externalKey schon existierte."
    value: ${{ steps.run.outputs.change-id }}
runs:
  using: composite
  steps:
    - id: run
      shell: bash
      env:
        KNOOING_MODE: ${{ inputs.mode }}
        KNOOING_API_URL: ${{ inputs.api-url }}
        KNOOING_API_KEY: ${{ inputs.api-key }}
        KNOOING_SERVICE_ID: ${{ inputs.service-id }}
        KNOOING_CHANGE_TITLE: ${{ inputs.title }}
        KNOOING_CHANGE_DESCRIPTION: ${{ inputs.description }}
        KNOOING_IMPACT: ${{ inputs.impact }}
        KNOOING_URGENCY: ${{ inputs.urgency }}
        KNOOING_CHANGE_CLASS: ${{ inputs.change-class }}
        KNOOING_ROLLBACK_PLAN: ${{ inputs.rollback-plan }}
        KNOOING_EXTERNAL_KEY: ${{ inputs.external-key }}
        KNOOING_CHANGE_ID: ${{ inputs.change-id }}
        KNOOING_OUTCOME: ${{ inputs.outcome }}
        KNOOING_NOTE: ${{ inputs.note }}
      run: |
        echo "::add-mask::$KNOOING_API_KEY"
        KNOOING_OUTPUT_FILE="$RUNNER_TEMP/knooing-change.env"
        export KNOOING_OUTPUT_FILE
        KNOOING_RESPONSE_FILE="$RUNNER_TEMP/knooing-response.json"
        export KNOOING_RESPONSE_FILE
        case "$KNOOING_MODE" in
          open)
            # --- knooing-open:begin
            set -eu
            (set -o pipefail) 2>/dev/null && set -o pipefail || true
            resp="${KNOOING_RESPONSE_FILE:-knooing-response.json}"
            : "${KNOOING_API_KEY:?KNOOING_API_KEY fehlt (maskierte CI-Variable)}"
            : "${KNOOING_SERVICE_ID:?KNOOING_SERVICE_ID fehlt}"
            body=$(jq -n \
              --arg serviceId "$KNOOING_SERVICE_ID" \
              --arg title "$KNOOING_CHANGE_TITLE" \
              --arg description "$KNOOING_CHANGE_DESCRIPTION" \
              --argjson impact "$KNOOING_IMPACT" \
              --argjson urgency "$KNOOING_URGENCY" \
              --arg changeClass "$KNOOING_CHANGE_CLASS" \
              --arg rollbackPlan "${KNOOING_ROLLBACK_PLAN:-}" \
              --arg externalKey "${KNOOING_EXTERNAL_KEY:-}" \
              '{serviceId: $serviceId, title: $title, description: $description, impact: $impact, urgency: $urgency, changeClass: $changeClass}
               + (if $rollbackPlan == "" then {} else {rollbackPlan: $rollbackPlan} end)
               + (if $externalKey == "" then {} else {externalKey: $externalKey} end)')
            http=$(curl -sS --max-time 30 -o "$resp" -w '%{http_code}' \
              -X POST "${KNOOING_API_URL%/}/api/pipeline/changes" \
              -H "X-API-Key: $KNOOING_API_KEY" -H 'Content-Type: application/json' \
              --data "$body")
            case "$http" in
              201)
                id=$(jq -r '.changeRecord.id' "$resp")
                echo "knooing: Change angelegt (Vorgang $(jq -r '.ticket.number' "$resp"), Change-Datensatz $id)."
                printf 'KNOOING_CHANGE_ID=%s\n' "$id" > "${KNOOING_OUTPUT_FILE:-knooing-change.env}"
                ;;
              200)
                id=$(jq -r '.changeRecordId // empty' "$resp")
                echo "knooing: Change mit diesem externalKey existiert bereits (Vorgang $(jq -r '.ticketId' "$resp"), Change-Datensatz ${id:-unbekannt}), es wurde nichts angelegt."
                printf 'KNOOING_CHANGE_ID=%s\n' "$id" > "${KNOOING_OUTPUT_FILE:-knooing-change.env}"
                ;;
              *)
                echo "knooing: Anlage fehlgeschlagen (HTTP $http): $(jq -r '.error // "unbekannt"' "$resp" 2>/dev/null) [$(jq -r '.code // "-"' "$resp" 2>/dev/null)]" >&2
                exit 1
                ;;
            esac
            # --- knooing-open:end
            echo "change-id=$(sed -n 's/^KNOOING_CHANGE_ID=//p' "$KNOOING_OUTPUT_FILE")" >> "$GITHUB_OUTPUT"
            ;;
          status)
            # --- knooing-status:begin
            set -eu
            (set -o pipefail) 2>/dev/null && set -o pipefail || true
            resp="${KNOOING_RESPONSE_FILE:-knooing-response.json}"
            : "${KNOOING_API_KEY:?KNOOING_API_KEY fehlt (maskierte CI-Variable)}"
            if [ -z "${KNOOING_CHANGE_ID:-}" ]; then
              echo "knooing: keine Change-ID vorhanden (Change wurde nicht neu angelegt), Status wird nicht gemeldet."
              exit 0
            fi
            body=$(jq -n --arg outcome "$KNOOING_OUTCOME" --arg note "${KNOOING_NOTE:-}" \
              '{outcome: $outcome} + (if $note == "" then {} else {note: $note} end)')
            http=$(curl -sS --max-time 30 -o "$resp" -w '%{http_code}' \
              -X POST "${KNOOING_API_URL%/}/api/pipeline/changes/$KNOOING_CHANGE_ID/status" \
              -H "X-API-Key: $KNOOING_API_KEY" -H 'Content-Type: application/json' \
              --data "$body")
            if [ "$http" != "200" ]; then
              echo "knooing: Statusmeldung fehlgeschlagen (HTTP $http): $(jq -r '.error // "unbekannt"' "$resp" 2>/dev/null) [$(jq -r '.code // "-"' "$resp" 2>/dev/null)]" >&2
              exit 1
            fi
            echo "knooing: Ergebnis $KNOOING_OUTCOME für Change $KNOOING_CHANGE_ID gemeldet."
            # --- knooing-status:end
            ;;
          *)
            echo "knooing: mode muss open oder status sein." >&2
            exit 1
            ;;
        esac
