name: Webhook Upgrade Validation

on:
  push:
    branches:
      - master
      - release-*
    tags:
      - v*
  workflow_dispatch: {}
  pull_request:
    branches:
      - master
      - release-*

permissions:
  contents: read

env:
  GO_VERSION: '1.23.8'

jobs:
  webhook-upgrade-check:
    runs-on: ubuntu-22.04
    timeout-minutes: 30
    steps:
      - name: Check out code into the Go module directory
        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

      - name: Setup Env
        uses: ./.github/actions/env-setup

      - name: Setup KinD
        run: |
          go install sigs.k8s.io/kind@v0.29.0
          kind delete cluster || true
          kind create cluster --image=kindest/node:v1.31.9

      - name: Install KubeVela CLI
        run: curl -fsSL https://kubevela.io/script/install.sh | bash

      - name: Install KubeVela baseline
        run: |
          vela install --set featureGates.enableCueValidation=true
          kubectl wait --namespace vela-system --for=condition=Available deployment/kubevela-vela-core --timeout=300s

      - name: Prepare failing chart changes
        run: |
          cat <<'CHART' > charts/vela-core/templates/defwithtemplate/resource.yaml
          # Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
          # Definition source cue file: vela-templates/definitions/internal/resource.cue
          apiVersion: core.oam.dev/v1beta1
          kind: TraitDefinition
          metadata:
            annotations:
              definition.oam.dev/description: Add resource requests and limits on K8s pod for your workload which follows the pod spec in path 'spec.template.'
            name: resource
            namespace: {{ include "systemDefinitionNamespace" . }}
          spec:
            appliesToWorkloads:
              - deployments.apps
              - statefulsets.apps
              - daemonsets.apps
              - jobs.batch
              - cronjobs.batch
            podDisruptive: true
            schematic:
              cue:
                template: |2
                  let resourceContent = {
                    resources: {
                      if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ {
                        // +patchStrategy=retainKeys
                        requests: {
                          cpu:    parameter.cpu
                          memory: parameter.memory
                        }
                        // +patchStrategy=retainKeys
                        limits: {
                          cpu:    parameter.cpu
                          memory: parameter.memory
                        }
                      }
                      if parameter.requests != _|_ {
                        // +patchStrategy=retainKeys
                        requests: {
                          cpu:    parameter.requests.cpu
                          memory: parameter.requests.memory
                        }
                      }
                      if parameter.limits != _|_ {
                        // +patchStrategy=retainKeys
                        limits: {
                          cpu:    parameter.limits.cpu
                          memory: parameter.limits.memory
                        }
                      }
                    }
                  }
                  if context.output.spec != _|_ if context.output.spec.template != _|_ {
                    patch: spec: template: spec: {
                      // +patchKey=name
                      containers: [resourceContent]
                    }
                  }
                  if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ {
                    patch: spec: jobTemplate: spec: template: spec: {
                      // +patchKey=name
                      containers: [resourceContent]
                    }
                  }
                  parameter: {
                    // +usage=Specify the amount of cpu for requests and limits
                    cpu?: *1 | number | string
                    // +usage=Specify the amount of memory for requests and limits
                    memory?: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
                    // +usage=Specify the resources in requests
                    requests?: {
                      // +usage=Specify the amount of cpu for requests
                      cpu: *1 | number | string
                      // +usage=Specify the amount of memory for requests
                      memory: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
                    }
                    // +usage=Specify the resources in limits
                    limits?: {
                      // +usage=Specify the amount of cpu for limits
                      cpu: *1 | number | string
                      // +usage=Specify the amount of memory for limits
                      memory: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
                    }
                  }

      - name: Load image
        run: |
          mkdir -p $HOME/tmp/
          TMPDIR=$HOME/tmp/ make image-load

      - name: Run Helm upgrade (expected to fail)
        run: |
          set +e
          helm upgrade \
            --set image.repository=vela-core-test \
            --set image.tag=$(git rev-parse --short HEAD) \
            --set featureGates.enableCueValidation=true \
            --wait kubevela ./charts/vela-core --debug -n vela-system
          status=$?
          echo "Helm upgrade exit code: ${status}"
          if [ $status -eq 0 ]; then
            echo "Expected helm upgrade to fail" >&2
            exit 1
          fi
          echo "Helm upgrade failed as expected"

      - name: Dump webhook configurations
        if: ${{ always() }}
        run: |
          kubectl get mutatingwebhookconfiguration kubevela-vela-core-admission -o yaml
          kubectl get validatingwebhookconfiguration kubevela-vela-core-admission -o yaml

      - name: Verify webhook validation remains active
        run: ginkgo -v --focus-file requiredparam_validation_test.go ./test/e2e-test

      - name: Cleanup kind cluster
        if: ${{ always() }}
        run: kind delete cluster --name kind