Skip to content
Snippets Groups Projects
Jenkinsfile.e2e 30.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
     * Ministerpräsidenten des Landes Schleswig-Holstein
     * Staatskanzlei
     * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
     *
     * Lizenziert unter der EUPL, Version 1.2 oder - sobald
     * diese von der Europäischen Kommission genehmigt wurden -
     * Folgeversionen der EUPL ("Lizenz");
     * Sie dürfen dieses Werk ausschließlich gemäß
     * dieser Lizenz nutzen.
     * Eine Kopie der Lizenz finden Sie hier:
     *
     * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
     *
     * Sofern nicht durch anwendbare Rechtsvorschriften
     * gefordert oder in schriftlicher Form vereinbart, wird
     * die unter der Lizenz verbreitete Software "so wie sie
     * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
     * ausdrücklich oder stillschweigend - verbreitet.
     * Die sprachspezifischen Genehmigungen und Beschränkungen
     * unter der Lizenz sind dem Lizenztext zu entnehmen.
     */
    
    OZGCloud's avatar
    OZGCloud committed
    import groovy.json.JsonOutput
    
    
    OZGCloud's avatar
    OZGCloud committed
    def SKIP_RUN = false
    
    
    pipeline {
    
      agent {
        node {
          label 'ozgcloud-jenkins-build-agent-jdk21-node20'
    
      triggers {
        // upstream(upstreamProjects: getUpstreamProjects(), threshold: hudson.model.Result.SUCCESS)
        cron('0 18-23,0-5 * * *')
      }
    
      environment {
        JENKINS_URL = "https://jenkins.infra.ozg-cloud.systems/job/codeSH_E2E/job/${env.BRANCH_NAME}/${env.BUILD_NUMBER}/"
        BUNDESLAND = "by"
        SSO_URL = "sso.dev.by.ozg-cloud.de"
        CLUSTER_BASE_URL = "dev.by.ozg-cloud.de"
        FAILED_STAGE = ""
        FAILED_PARALLEL_STAGE = " "
        EA_BEZEICHNER = generateBezeichner("e2e-ea")
        MAIN_BEZEICHNER = generateBezeichner("e2e-main")
        ADMIN_BEZEICHNER = generateBezeichner("e2e-admin")
        SH_SUCCESS_STATUS_CODE = 0
        FORCE_COLOR = 0
        NO_COLOR = 1
        NX_DISABLE_DB = true
        KEYCLOAK_CLIENT_ADMIN_APP = "admin"
        KEYCLOAK_CLIENT_ALFA_APP = "alfa"
      }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      options {
        timeout(time: 2, unit: 'HOURS')
        disableConcurrentBuilds()
        buildDiscarder(logRotator(numToKeepStr: '15'))
        skipDefaultCheckout(true)
      }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      stages {
        stage('Checkout build trigger') {
          when {
            not {
              anyOf {
                triggeredBy 'UpstreamCause'
                triggeredBy 'BuildUpstreamCause'
                triggeredBy cause: 'UserIdCause'
                triggeredBy 'TimerTrigger'
              }
    
          }
          steps {
            script {
              SKIP_RUN = true
              currentBuild.result = "UNSTABLE"
    
          }
        }
        stage('Check branch') {
          when {
            triggeredBy 'TimerTrigger'
          }
          steps {
            script {
              if (!isMainBranch()) {
                echo "Branchname " + env.BRANCH_NAME + " does not match, skipping e2e tests"
                SKIP_RUN = true
              }
    
          }
        }
        stage('Checkout SCM') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              checkout scm
            }
          }
        }
        stage("Clone Gitops Repo") {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              cloneGitopsRepo()
            }
          }
        }
    
        stage("Init Default Versions") {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              initEnvAdminDefaultVersions()
              initEnvAlfaDefaultVersions()
              initEnvAlfaClientDefaultVersion()
              initEnvVorgangManagerDefaultVersions()
              initEnvUserManagerDefaultVersions()
    
        stage("Set User Versions") {
          when {
            expression { !SKIP_RUN }
            beforeInput true
            triggeredBy cause: "UserIdCause"
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              catchError {
                timeout(time: 5, unit: 'MINUTES') {
                  userVersions = input message: "Edit Default Values",
                    parameters: [
                      string(name: "AlfaImageTag", defaultValue: env.ALFA_IMAGE_TAG, trim: true),
                      string(name: "AlfaHelmChartVersion", defaultValue: env.ALFA_HELM_CHART_VERSION, trim: true),
                      string(name: "AlfaHelmRepoUrl", defaultValue: env.ALFA_HELM_REPO_URL, trim: true),
    
                      string(name: "AlfaClientImageTag", defaultValue: env.ALFA_CLIENT_IMAGE_TAG, trim: true),
                      string(name: "AlfaClientHelmChartVersion", defaultValue: env.ALFA_CLIENT_HELM_CHART_VERSION, trim: true),
                      string(name: "AlfaClientHelmRepoUrl", defaultValue: env.ALFA_CLIENT_HELM_REPO_URL, trim: true),
    
                      string(name: "AdministrationImageTag", defaultValue: env.ADMINISTRATION_IMAGE_TAG, trim: true),
                      string(name: "AdministrationHelmChartVersion", defaultValue: env.ADMINISTRATION_HELM_CHART_VERSION, trim: true),
                      string(name: "AdministrationHelmRepoUrl", defaultValue: env.ADMINISTRATION_HELM_REPO_URL, trim: true),
                      string(name: "AdminClientImageTag", defaultValue: env.ADMIN_CLIENT_IMAGE_TAG, trim: true),
                      string(name: "AdminClientHelmChartVersion", defaultValue: env.ADMIN_CLIENT_HELM_CHART_VERSION, trim: true),
                      string(name: "AdminClientHelmRepoUrl", defaultValue: env.ADMIN_CLIENT_HELM_REPO_URL, trim: true),
                      string(name: "VorgangManagerImageTag", defaultValue: env.VORGANG_MANAGER_IMAGE_TAG, trim: true),
                      string(name: "VorgangManagerHelmChartVersion", defaultValue: env.VORGANG_MANAGER_HELM_CHART_VERSION, trim: true),
                      string(name: "VorgangManagerHelmRepoUrl", defaultValue: env.VORGANG_MANAGER_HELM_REPO_URL, trim: true),
                      string(name: "UserManagerImageTag", defaultValue: env.USER_MANAGER_IMAGE_TAG, trim: true),
                      string(name: "UserManagerHelmChartVersion", defaultValue: env.USER_MANAGER_HELM_CHART_VERSION, trim: true),
                      string(name: "UserManagerHelmRepoUrl", defaultValue: env.USER_MANAGER_HELM_REPO_URL, trim: true)
                    ]
    
                  initEnvUserVersions(userVersions)
    
        stage('Init k8s') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              configFileProvider([configFile(fileId: 'kubeconfig-dev-okd-cluster', variable: 'KUBE_CONFIG')]) {
                sh 'mkdir ~/.kube'
                sh 'cp ${KUBE_CONFIG} ~/.kube/config'
              }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              sh 'helm version'
    
    OZGCloud's avatar
    OZGCloud committed
            }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        stage('Rollout E2E Namespaces') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              checkoutGitopsE2eBranch()
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER])
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              generateNamespaces()
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              pushGitopsRepo()
            }
          }
          post {
            failure {
              script {
                deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER])
              }
    
        stage("Install Cypress") {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              withNPM(npmrcConfig: 'npm-nexus-auth') {
                sh 'pnpm --version'
                dir('alfa-client') {
                  sh 'pnpm install --frozen-lockfile --network-concurrency=8'
                  sh "pnpm run cypress:install"
    
        stage('Wait for Rollout E2E Namespaces') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
    OZGCloud's avatar
    OZGCloud committed
    
    
              waitForAdminRollout(env.ADMIN_BEZEICHNER)
              waitForAlfaRollout([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER])
            }
          }
          post {
            failure {
              script {
                deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER])
              }
    
    OZGCloud's avatar
    OZGCloud committed
            }
    
        stage('Init PortForwards') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              forwardElasticSearch()
    
        //stage('Run E2E-Tests') {
        //    when {
        //        expression { !SKIP_RUN }
        //    }
        //    failFast false
    
        //    parallel {
        stage('E2E-Alfa-EA') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
              script {
                def bezeichner = env.EA_BEZEICHNER
    
                Integer mongoDbPort = forwardMongoDbPort(generateNamespace(bezeichner))
    
                runTests(bezeichner, 'alfa-e2e', 'einheitlicher-ansprechpartner', env.KEYCLOAK_CLIENT_ALFA_APP, mongoDbPort, env.STAGE_NAME)
    
                stopForwardMongoDbPort(generateNamespace(bezeichner))
              }
    
          }
          post {
            failure {
              script {
                FAILED_PARALLEL_STAGE += "${env.STAGE_NAME} "
              }
            }
            always {
              script {
                publishAlfaE2ETestResult("einheitlicher-ansprechpartner", "Alfa E2E-Tests EA")
              }
            }
          }
        }
    
        stage('E2E-Alfa-Main') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
              script {
                def bezeichner = env.MAIN_BEZEICHNER
    
                Integer mongoDbPort = forwardMongoDbPort(generateNamespace(bezeichner))
    
                runTests(bezeichner, 'alfa-e2e', 'main-tests', env.KEYCLOAK_CLIENT_ALFA_APP, mongoDbPort, env.STAGE_NAME)
    
                stopForwardMongoDbPort(generateNamespace(bezeichner))
              }
            }
          }
          post {
            failure {
              script {
                FAILED_PARALLEL_STAGE += "${env.STAGE_NAME} "
              }
            }
            always {
              script {
                publishAlfaE2ETestResult("main-tests", "Alfa E2E-Tests main")
              }
            }
          }
    
    OZGCloud's avatar
    OZGCloud committed
        }
    
        stage('E2E-Admin-Main') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
              script {
                String bezeichner = env.ADMIN_BEZEICHNER
    
                Integer mongoDbPort = forwardMongoDbPort(generateNamespace(bezeichner))
    
                runTests(bezeichner, 'admin-e2e', 'main-tests', env.KEYCLOAK_CLIENT_ADMIN_APP, mongoDbPort, env.STAGE_NAME)
    
                stopForwardMongoDbPort(generateNamespace(bezeichner))
              }
            }
          }
          post {
    
    OZGCloud's avatar
    OZGCloud committed
            failure {
    
              script {
                FAILED_PARALLEL_STAGE += "${env.STAGE_NAME} "
              }
            }
            always {
              script {
                publishAdminE2ETestResult()
              }
            }
          }
        }
        //    }
        //}
    
        stage('Delete E2E Namespaces') {
          when {
            expression { !SKIP_RUN }
          }
          steps {
            script {
              FAILED_STAGE = env.STAGE_NAME
    
              deleteNamespaces([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER, env.ADMIN_BEZEICHNER])
            }
          }
        }
    
      }
      post {
        failure {
          script {
            if (isMainBranch() || isReleaseBranch()) {
              sendFailureMessage()
    
    }
    
    String getUpstreamProjects() {
    
      if (isMainBranch() || isReleaseBranch()) {
        return "alfa/${env.BRANCH_NAME},vorgang-manager/${env.BRANCH_NAME},user-manager/${env.BRANCH_NAME}"
      }
    
    }
    
    def cloneGitopsRepo() {
    
      final email = "jenkins@ozg-sh.de"
      final name = "jenkins"
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) {
        sh 'git clone https://${USER}:${TOKEN}@git.ozg-sh.de/ozgcloud-devops/gitops.git'
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        dir("gitops") {
          sh "git config user.email '${email}'"
          sh "git config user.name '${name}'"
    
    }
    
    Map getApplicationValues(String application) {
    
      def applicationValues = readYaml file: "gitops/${getEnvironment()}/application/values/${application}-values.yaml"
    
      return applicationValues.get(application.replaceAll("-", "_"))
    
    }
    
    String getEnvironment() {
    
      if (isReleaseBranch()) {
        return "test"
      }
    
      return "dev"
    
    }
    
    String getImageTag(Map applicationValues) {
    
      return applicationValues.image.tag
    
    }
    
    String getHelmChartVersion(Map applicationValues) {
    
      return applicationValues.helm.version
    
    Boolean isMainBranch() {
    
      return env.BRANCH_NAME == 'main'
    
    OZGCloud's avatar
    OZGCloud committed
    String getHelmRepoUrl() {
    
      if (isReleaseBranch()) {
        return "https://nexus.ozg-sh.de/repository/ozg-base-apps"
      }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return "https://nexus.ozg-sh.de/repository/ozg-base-apps-snapshot"
    
    Void initEnvAdminDefaultVersions() {
      def values = getApplicationValues('administration')
      env.ADMINISTRATION_IMAGE_TAG = getImageTag(values)
      env.ADMINISTRATION_HELM_CHART_VERSION = getHelmChartVersion(values)
      env.ADMINISTRATION_HELM_REPO_URL = getHelmRepoUrl()
    
    
    Martin's avatar
    Martin committed
      values = getApplicationValues('administration-client')
    
      env.ADMIN_CLIENT_IMAGE_TAG = getImageTag(values)
      env.ADMIN_CLIENT_HELM_CHART_VERSION = getHelmChartVersion(values)
      env.ADMIN_CLIENT_HELM_REPO_URL = getHelmRepoUrl()
    }
    
    Void initEnvAlfaDefaultVersions() {
    
      def values = getApplicationValues('alfa')
    
      env.ALFA_IMAGE_TAG = getImageTag(values)
      env.ALFA_HELM_CHART_VERSION = getHelmChartVersion(values)
      env.ALFA_HELM_REPO_URL = getHelmRepoUrl()
    }
    
    Void initEnvAlfaClientDefaultVersion() {
      def values = getApplicationValues('alfa-client')
    
      env.ALFA_CLIENT_IMAGE_TAG = getImageTag(values)
      env.ALFA_CLIENT_HELM_CHART_VERSION = getHelmChartVersion(values)
      env.ALFA_CLIENT_HELM_REPO_URL = getHelmRepoUrl()
    
    Void initEnvVorgangManagerDefaultVersions() {
    
      def values = getApplicationValues('vorgang-manager')
    
      env.VORGANG_MANAGER_IMAGE_TAG = getImageTag(values)
      env.VORGANG_MANAGER_HELM_CHART_VERSION = getHelmChartVersion(values)
      env.VORGANG_MANAGER_HELM_REPO_URL = getHelmRepoUrl()
    
    }
    
    Void initEnvUserManagerDefaultVersions() {
    
      def values = getApplicationValues('user-manager')
    
      env.USER_MANAGER_IMAGE_TAG = getImageTag(values)
      env.USER_MANAGER_HELM_CHART_VERSION = getHelmChartVersion(values)
      env.USER_MANAGER_HELM_REPO_URL = getHelmRepoUrl()
    
    }
    
    Void initEnvUserVersions(userVersions) {
    
      env.ALFA_IMAGE_TAG = userVersions.AlfaImageTag
      env.ALFA_CLIENT_IMAGE_TAG = userVersions.AlfaClientImageTag
      env.ALFA_HELM_CHART_VERSION = userVersions.AlfaHelmChartVersion
      env.ALFA_HELM_REPO_URL = userVersions.AlfaHelmRepoUrl
      env.ADMINISTRATION_IMAGE_TAG = userVersions.AdministrationImageTag
      env.ADMINISTRATION_HELM_CHART_VERSION = userVersions.AdministrationHelmChartVersion
      env.ADMINISTRATION_HELM_REPO_URL = userVersions.AdministrationHelmRepoUrl
      env.ADMIN_CLIENT_IMAGE_TAG = userVersions.AdminClientImageTag
      env.ADMIN_CLIENT_HELM_CHART_VERSION = userVersions.AdminClientHelmChartVersion
      env.ADMIN_CLIENT_HELM_REPO_URL = userVersions.AdminClientHelmRepoUrl
      env.VORGANG_MANAGER_IMAGE_TAG = userVersions.VorgangManagerImageTag
      env.VORGANG_MANAGER_HELM_CHART_VERSION = userVersions.VorgangManagerHelmChartVersion
      env.VORGANG_MANAGER_HELM_REPO_URL = userVersions.VorgangManagerHelmRepoUrl
      env.USER_MANAGER_IMAGE_TAG = userVersions.UserManagerImageTag
      env.USER_MANAGER_HELM_CHART_VERSION = userVersions.UserManagerHelmChartVersion
      env.USER_MANAGER_HELM_REPO_URL = userVersions.UserManagerHelmRepoUrl
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    
    Void pushGitopsRepo() {
    
      withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) {
        dir('gitops') {
          if (hasUnpushedCommits()) {
            sh 'git config pull.rebase false'
            sh 'git pull'
            sh 'git push https://${USER}:${TOKEN}@git.ozg-sh.de/ozgcloud-devops/gitops.git'
          }
    
    OZGCloud's avatar
    OZGCloud committed
        }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Boolean hasUnpushedCommits() {
    
      return sh(script: "git cherry -v | grep .", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Void checkoutGitopsE2eBranch() {
    
      dir('gitops') {
        sh 'git checkout e2e'
      }
    
      def y1 = generateAdminNamespaceYaml()
    
      def y2 = generateEaNamespaceYaml()
      def y3 = generateMainNamespaceYaml()
    
        sh "git add ${y1} ${y2} ${y3}"
    
        sh "git commit -m 'add e2e namespaces for testrun'"
      }
    
    }
    
    
    Void generateAdminNamespaceYaml() {
      def bezeichner = env.ADMIN_BEZEICHNER
      def envValues
    
      dir("alfa-client/apps/admin-e2e/") {
    
        envValues = readYaml file: "src/fixtures/argocd/by-admin-dev.yaml";
    
        envValues.ozgcloud.bezeichner = bezeichner
        envValues.administration.put("image", ['tag': env.ADMINISTRATION_IMAGE_TAG])
        envValues.administration.put("helm", ['version': env.ADMINISTRATION_HELM_CHART_VERSION, 'repoUrl': env.ADMINISTRATION_HELM_REPO_URL])
    
        envValues.administration.put("ozgcloud", ['feature': ['organisationsEinheiten': "true"], 'organisationEinheit': ['zufiSearchUri': generateZufiSearchUri(bezeichner)]])
    
    Martin's avatar
    Martin committed
        envValues.administration_client.put("image", ['tag': env.ADMIN_CLIENT_IMAGE_TAG])
        envValues.administration_client.put("helm", ['version': env.ADMIN_CLIENT_HELM_CHART_VERSION, 'repoUrl': env.ADMIN_CLIENT_HELM_REPO_URL])
    
      return writeYamlToGitOps(bezeichner, envValues);
    
    String generateZufiSearchUri(String bezeichner) {
    
      return "https://${bezeichner}.dev.by.ozg-cloud.de/api/organisationseinheits?searchBy={searchBy}"
    
    String generateEaNamespaceYaml() {
    
      return generateNamespaceYaml(env.EA_BEZEICHNER, "by-ea-dev.yaml");
    
    String generateMainNamespaceYaml() {
    
      return generateNamespaceYaml(env.MAIN_BEZEICHNER, "by-main-dev.yaml");
    
    String generateNamespaceYaml(String bezeichner, String valuesPathSuffix) {
    
      def envValues
      dir('alfa-client/apps/alfa-e2e/') {
        envValues = readYaml file: "src/fixtures/argocd/" + valuesPathSuffix;
    
        envValues.ozgcloud.bezeichner = bezeichner
        envValues.alfa.put("image", ['tag': env.ALFA_IMAGE_TAG])
        envValues.alfa.put("helm", ['version': env.ALFA_HELM_CHART_VERSION, 'repoUrl': env.ALFA_HELM_REPO_URL])
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        envValues.alfa_client.put("image", ['tag': env.ALFA_CLIENT_IMAGE_TAG])
        envValues.alfa_client.put("helm", ['version': env.ALFA_CLIENT_HELM_CHART_VERSION, 'repoUrl': env.ALFA_CLIENT_HELM_REPO_URL])
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        envValues.vorgang_manager.put("image", ['tag': env.VORGANG_MANAGER_IMAGE_TAG])
        envValues.vorgang_manager.put("helm", ['version': env.VORGANG_MANAGER_HELM_CHART_VERSION, 'repoUrl': env.VORGANG_MANAGER_HELM_REPO_URL])
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        envValues.user_manager.put("image", ['tag': env.USER_MANAGER_IMAGE_TAG])
        envValues.user_manager.put("helm", ['version': env.USER_MANAGER_HELM_CHART_VERSION, 'repoUrl': env.USER_MANAGER_HELM_REPO_URL])
      }
    
      return writeYamlToGitOps(bezeichner, envValues);
    
    OZGCloud's avatar
    OZGCloud committed
    
    
    String writeYamlToGitOps(String bezeichner, Object envValues) {
    
      def bezeichnerYaml = "dev/namespace/namespaces/by-${bezeichner}-dev.yaml"
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      writeYaml file: "gitops/${bezeichnerYaml}", data: envValues, overwrite: true
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return bezeichnerYaml;
    
    Void deleteNamespaces(ozgCloudBezeichner) {
    
      for (bezeichner in ozgCloudBezeichner) {
        if (hasNamespaceFile(bezeichner)) {
          removeNamespaceFile(bezeichner)
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      pushGitopsRepo()
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      for (bezeichner in ozgCloudBezeichner) {
        waitForDeletion(bezeichner)
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Void removeNamespaceFile(String bezeichner) {
    
      dir("gitops/dev/namespace/namespaces") {
        sh "rm by-${bezeichner}-dev.yaml"
        sh "git add by-${bezeichner}-dev.yaml"
        sh "git commit -m 'delete e2e by-${bezeichner}-dev.yaml'"
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Boolean hasNamespaceFile(String bezeichner) {
    
      return sh(script: "ls gitops/dev/namespace/namespaces | grep 'by-${bezeichner}-dev.yaml'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Void waitForDeletion(String bezeichner) {
    
    Martin's avatar
    Martin committed
        sh "kubectl wait --for=delete applications/by-${bezeichner}-dev-application -n argocd --timeout=120s"
    
      } catch (Exception e) {
    
    Martin's avatar
    Martin committed
          sh """
          kubectl patch applications.argoproj.io by-${bezeichner}-dev-application -n argocd --type=json -p '[{"op": "remove", "path": "/metadata/finalizers"}]'
          """
          sh "kubectl wait --for=delete applications/by-${bezeichner}-dev-application -n argocd --timeout=120s"
    
        } catch (Exception e2) {
          error("Application by-${bezeichner}-dev-application konnte nicht gelöscht werden")
        }
    
    OZGCloud's avatar
    OZGCloud committed
    Void waitForAlfaRollout(ozgCloudBezeichner) {
    
      for (bezeichner in ozgCloudBezeichner) {
        waitForAlfaRollout(bezeichner)
      }
    
    Void waitForAdminRollout(String bezeichner) {
    
    OZGCloud's avatar
    OZGCloud committed
      waitForAlfaRollout([bezeichner])
    
      waitForHealthyApplication(bezeichner, 'administration')
    
    Martin's avatar
    Martin committed
      waitForHealthyApplication(bezeichner, 'administration-client')
    
    }
    
    Void waitForAlfaRollout(String bezeichner) {
    
      waitForHealthyApplication(bezeichner, 'application')
      waitForHealthyApplication(bezeichner, 'vorgang-manager')
      waitForHealthyApplication(bezeichner, 'user-manager')
      waitForHealthyApplication(bezeichner, 'alfa')
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Void waitForHealthyApplication(String bezeichner, String application) {
    
      try {
        def countRetry = 0
        def maxRetry = 24
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        while (!isApplicationPresent(bezeichner, application) && countRetry < maxRetry) {
          countRetry++
          sh "sleep 20"
        }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        if (!isApplicationHealthy(bezeichner, application)) {
          waitForHealthyStatus(bezeichner, application)
    
    OZGCloud's avatar
    OZGCloud committed
        }
    
      } catch (Exception e) {
        echo "waitForHealthyApplication Exception: ${e}"
        error("Application ${application} unhealthy")
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Boolean isApplicationPresent(String bezeichner, String application) {
    
      return sh(script: "kubectl get applications -n argocd | grep 'by-${bezeichner}-dev-${application}'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Boolean isApplicationHealthy(String bezeichner, String application) {
    
      return sh(script: "kubectl get application/by-${bezeichner}-dev-${application} -n argocd -o=jsonpath='{.status.health.status}' | grep Healthy", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Void waitForHealthyStatus(String bezeichner, String application) {
    
      sh "kubectl wait --for=jsonpath='{.status.health.status}'=Healthy applications/by-${bezeichner}-dev-${application} -n argocd --timeout=900s"
    
    Void publishAlfaE2ETestResult(String appVariant, String reportName) {
      publishE2ETestResult("alfa-e2e", appVariant, reportName);
    
    Void publishAdminE2ETestResult() {
      publishE2ETestResult("admin-e2e", "main-tests", "Admin E2E-Tests main");
    
    OZGCloud's avatar
    OZGCloud committed
    
    
    Void publishE2ETestResult(String appName, String appVariant, String reportName) {
    
      def reportDir = "alfa-client/apps/" + appName + "/reports/" + appVariant;
    
      publishHTML(
    
          allowMissing         : false,
    
          keepAll              : true,
          reportDir            : reportDir,
          reportFiles          : 'report.html',
          reportName           : reportName
    
    OZGCloud's avatar
    OZGCloud committed
    String runTests(String bezeichner, String appName, String appVariant, String keycloakClientName, Integer dbPort, String stageName) {
      def config = generateCypressConfig(bezeichner, appName, appVariant, keycloakClientName, dbPort)
    
        dir('alfa-client') {
    
    OZGCloud's avatar
    OZGCloud committed
          sh "pnpm run cypress:version"
    
          sh "apps/run-tests.sh ${appName} ${appVariant} ${config}"
    
    OZGCloud's avatar
    OZGCloud committed
        }
    
      } catch (Exception e) {
        printNpmDebugLog()
    
        error("Fehler in Stage ${stageName}")
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Void printNpmDebugLog() {
    
      if (hasNpmDebugLog()) {
        sh "cat pnpm-debug.log"
      } else {
        echo "pnpm debug log not found"
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String makeUrlConform(String input) {
    
      return input.replaceAll(/[^a-zA-Z0-9]+/, "").toLowerCase()
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String generateBezeichner(String stage) {
    
      def branchName = makeUrlConform(env.BRANCH_NAME)
      def stageName = makeUrlConform(stage)
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return "${cutBranchNameForKeycloakRealm(branchName, stageName)}-${stageName}"
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String cutBranchNameForKeycloakRealm(String branchName, String stageName) {
    
      final maxKeycloakRealmLength = 30
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      def cutBranchNamePosition = maxKeycloakRealmLength - (stageName.length() + "${env.BUNDESLAND}---dev".length())
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return branchName.take(cutBranchNamePosition)
    
    OZGCloud's avatar
    OZGCloud committed
    String generateCypressConfig(String bezeichner, String appName, String appVariant, String keycloakClientName, Integer dbPort) {
    
      def namespace = generateNamespace(bezeichner)
    
      def configName = "cypress-ci-" + appVariant + ".json"
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      dir("alfa-client/apps/${appName}/") {
    
        def config = readJSON file: 'cypress-ci.json'
    
        def vorgangManagerDatabaseSecret = getVorgangManagerDatabaseSecret(namespace);
        def decodedPassword = decodeString(vorgangManagerDatabaseSecret.password);
        def parsablePassword = makePasswordUrlConform(decodedPassword);
    
        config.baseUrl = "https://${generateUrlBezeichner(bezeichner, appName)}.${env.CLUSTER_BASE_URL}" as String
    
        config.env.dbUrl = "mongodb://${decodeString(vorgangManagerDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true&socketTimeoutMS=30000&heartbeatFrequencyMS=10000" as String
        config.env.keycloakUrl = "https://${env.SSO_URL}/" as String
        config.env.keycloakRealm = namespace as String
    
    OZGCloud's avatar
    OZGCloud committed
        config.env.keycloakClient = keycloakClientName as String
    
        config.videosFolder = "./reports/${appVariant}/videos" as String
        config.screenshotsFolder = "./reports/${appVariant}/screenshots" as String
        config.reporterOptions.reportDir = "./reports/${appVariant}/mochawesome-report" as String
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        config.specPattern = "src/e2e/${appVariant}/**/*.cy.{js,jsx,ts,tsx}" as String
    
    OZGCloud's avatar
    OZGCloud committed
    
    
        config.env.put("search", getElasticsearchEnv(namespace))
        config.env.put("userManager", getUserManagerEnv(namespace, dbPort))
        config.env.put("smocker", getSmockerEnv(namespace))
    
        writeJSON file: configName, json: config
    
      return "cypress-ci-" + appVariant + ".config.ts"
    
    String generateUrlBezeichner(String bezeichner, String appName) {
      if (appName == 'admin-e2e') {
    
    Martin's avatar
    Martin committed
        return "${bezeichner}-administration";
    
      }
      return bezeichner;
    
    String makePasswordUrlConform(String password) {
    
      return sh(script: "printf %s ${password} | jq -sRr @uri", returnStdout: true);
    
    Map getVorgangManagerDatabaseSecret(String namespace) {
    
      return readJSON(text: sh(script: "kubectl get secret ozg-mongodb-admin-vorgang-manager-user -n ${namespace} -o jsonpath={.data}", returnStdout: true))
    
    Map getUserManagerEnv(String namespace, dbPort) {
      def userManagerDatabaseSecret = getUserManagerDatabaseSecret(namespace);
      def decodedPassword = decodeString(userManagerDatabaseSecret.password);
      def parsablePassword = makePasswordUrlConform(decodedPassword);
    
      return [
        "dbUrl"   : "mongodb://${decodeString(userManagerDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true&socketTimeoutMS=30000&heartbeatFrequencyMS=10000" as String,
        "database": "user-manager-database"
      ]
    
    OZGCloud's avatar
    OZGCloud committed
    Map getUserManagerDatabaseSecret(String namespace) {
    
      return readJSON(text: sh(script: "kubectl get secret ozg-mongodb-admin-user-manager-user -n ${namespace} -o jsonpath={.data}", returnStdout: true))
    
    OZGCloud's avatar
    OZGCloud committed
    Void sendFailureMessage() {
    
      def data = [
        "msgtype"       : "m.text",
        "body"          : "E2E-Tests: Failed stage: ${getFailedStage()} Build-ID: ${env.BUILD_NUMBER} Link: ${JENKINS_URL}" as String,
        "format"        : "org.matrix.custom.html",
        "formatted_body": "E2E-Tests: Failed stage: ${getFailedStage()} Build-ID: <a href='${JENKINS_URL}'>${env.BUILD_NUMBER}</a>" as String
      ]
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      sh "curl -XPOST -H 'authorization: Bearer ${getElementAccessToken()}' -d '${JsonOutput.toJson(data)}' https://matrix.ozg-sh.de/_matrix/client/v3/rooms/${getElementRoomId()}/send/m.room.message"
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String getFailedStage() {
    
      if (FAILED_PARALLEL_STAGE.trim()) {
        return FAILED_PARALLEL_STAGE.trim()
      }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return FAILED_STAGE
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String getElementRoomId() {
    
      final releaseRoomId = "!oWZpUGTFsxkJIYNfYg:matrix.ozg-sh.de"
      final masterRoomId = "!iQPAvQIiRwRpNOszjw:matrix.ozg-sh.de"
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      if (isReleaseBranch()) {
        return releaseRoomId
      }
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return masterRoomId
    
    Boolean isReleaseBranch() {
    
      return env.BRANCH_NAME == 'release'
    
    OZGCloud's avatar
    OZGCloud committed
    String getElementAccessToken() {
    
      withCredentials([string(credentialsId: 'element-login-json', variable: 'LOGIN_JSON')]) {
        return readJSON(text: sh(script: '''curl -XPOST -d \"$LOGIN_JSON\" https://matrix.ozg-sh.de/_matrix/client/v3/login''', returnStdout: true)).access_token
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Map getElasticsearchEnv(String namespace) {
    
      def elasticsearchSecret = getElasticsearchSecret(namespace)
    
    OZGCloud's avatar
    OZGCloud committed
    
    
      return [
        "user"    : decodeString(elasticsearchSecret.username),
        "password": decodeString(elasticsearchSecret.password),
        "index"   : decodeString(elasticsearchSecret.index),
        "url"     : "https://localhost:9200"
      ]
    
    Void forwardMongoDbPort(String namespace) {
    
      try {
        def minPort = 20000
        def portRange = 20000
        //def dbPort = "${Math.abs(new Random().nextInt(portRange+1))+minPort}" as Integer
        def dbPort = Math.abs(new Random().nextInt(portRange + 1)) + minPort
    
        echo "Forwarding MongoDB Port to local port ${dbPort}"
    
        def pidFile = generateMongoDbPortForwardPidFile(namespace)
    
        sh "kubectl port-forward ozg-mongodb-0 ${dbPort}:27017 -n ${namespace} & echo \$! > ${pidFile}"
    
        sh "sleep 20"
    
        return dbPort
      }
      catch (Exception e) {
        echo "forwardMongoDbPort Exception: ${e}"
        error("Error forwarding service")
      }
    
    Void stopForwardMongoDbPort(String namespace) {
    
      echo "Removing forwarding MongoDB Port to local port for ${namespace}"
      def pidFile = generateMongoDbPortForwardPidFile(namespace)
      dir('alfa-client/apps/alfa-e2e/src/jenkins-build-files') {
        sh "./kill-pid-by-filename.sh ${pidFile}"
      }
    
    }
    
    Void generateMongoDbPortForwardPidFile(String namespace) {
    
      return "/tmp/pid_file_mongodb_port_forward_${namespace}.pid"
    
    OZGCloud's avatar
    OZGCloud committed
    Void forwardElasticSearch() {
    
      if (!isElasticSearchForwarded()) {
        sh "kubectl port-forward ozg-search-cluster-es-ozg-search-0 9200:9200 -n elastic-system &"
      }
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Boolean isElasticSearchForwarded() {
    
      return sh(script: "lsof -i -P -n | grep LISTEN | grep :9200", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String generateNamespace(String bezeichner) {
    
      return "${env.BUNDESLAND}-${bezeichner}-dev"
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    String decodeString(String encoded) {
    
      return sh(script: "echo -n ${encoded} | base64 --decode", returnStdout: true)
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Map getElasticsearchSecret(String namespace) {
    
      return readJSON(text: sh(script: "kubectl get secret elasticsearch-credentials -n ${namespace} -o jsonpath={.data}", returnStdout: true))
    
    OZGCloud's avatar
    OZGCloud committed
    }
    
    Boolean hasNpmDebugLog() {
    
      return sh(script: "ls -l pnpm-debug.log", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    
    }
    
    Map getSmockerEnv(String namespace) {
    
      return [
        "url": "https://${namespace}-smocker.dev.by.ozg-cloud.de".toString()
      ]