// ## Jenkinsfile.wildfire.build-test-deploy ##

pipeline {
  agent { label 'master' }
  parameters {
    choice(name: 'REPO_BRANCH_OR_TAG', \
                 choices: '\
develop5\n\
release-5.14.1\n\
release-5.14.0\n\
5.14.0-rc1\n\
5.14.0-rc2\n\
5.14.0-rc3\n\
5.14.0-rc4\n\
5.14.0-rc5\n\
5.14.0\n\
develop5_roman_custom\n\
develop5_wd\n\
develop5-bg\n\
Use Existing Distro\
', \
                 description: 'Repo branch or tag that is to be built.  Branches begin with develop, master, release or maint.  Tags are anything else or "Use Existing Distro" for no build.')
    run(name: 'USE_EXISTING_DISTRO', \
              projectName: 'Wildfire/Wildfire-Build-Test-Deploy', \
              filter: 'STABLE', \
              description: 'Existing distro to be used if "Use Existing Distro" is specified above.  Selected from prior STABLE job runs.')
    choice(name: 'BUILD_FROM_HEAD', \
                 choices: 'No\nYes', \
                 description: 'Use module source repo HEAD rather than tag?  NOTE: Only allowed for "develop" branch.')
    choice(name: 'PROD_OR_DEV', \
                 choices: '\n-dev', \
                 description: 'Use production or development distro for testing: blank = production, -dev = development')
    string(name: 'CODECEPT_OPTIONS', \
                 defaultValue: '', \
                 description: 'Additional codeception options.  "--xml" is always used.')
    choice(name: 'DO_LOCAL_TEST', \
                 choices: 'No\nYes', \
                 description: 'Should a local distro test be performed on the new distro?')
    choice(name: 'RUN_MODULE_TESTS', \
                 choices: 'true\nfalse', \
                 description: 'Are module tests to be run?')
    choice(name: 'RUN_UNIT', \
                 choices: 'false\ntrue', \
                 description: 'Are unit test suites to be run?  For W5 this may result in an extra 30 minutes to install distro.')
    choice(name: 'RUN_SPECIAL_TESTS', \
                 choices: '\nqa', \
                 description: 'Are QA tests to be run?  May not work for "Use Existing Distro".')
    choice(name: 'RUN_DRUPAL_TESTS', \
                 choices: 'false\ntrue', \
                 description: 'Are Drupal tests to be run?')
    string(name: 'DRUPAL_TEST', \
                 defaultValue: '', \
                 description: 'Drupal test to run.  For example: "file some-drupal-tests" or "phpunit modules/contrib/stepbystep/tests/src/Functional/StepByStepTest.php"')
    choice(name: 'DEV', \
                 choices: 'Deploy and Test and Delete\n\nDeploy', \
                 description: 'What to do in the DEV environment.')
    choice(name: 'DEV_LOCATION', \
                 choices: 'da4\nda5\nda2', \
                 description: 'DEV server location: daN = dev-aegir-0N')
    string(name: 'TEST_MODULE', \
                 defaultValue: '', \
                 description: 'Distro module to be tested.  For example "custom/select_theme".  If blank, all modules will be tested.')
    string(name: 'TEST_FILE', \
                 defaultValue: '', \
                 description: 'Distro module test file to run.  For example "wildfireGoogleAnalyticsCest" or "wildfireGoogleAnalyticsCest:basicTest3".  If blank, all module test files will be run.')
    choice(name: 'SAVE_TEST_OUTPUT', \
                 choices: 'true\nfalse', \
                 description: 'Save test output in tar file?')
    choice(name: 'PROMPT_FOR_DEPLOY', \
                 choices: 'No\nYes', \
                 description: 'Wait at Deploy steps and prompt for Deploy or Abort job.')
    choice(name: 'WHEN_TESTS_FAIL', \
                 choices: 'Abort\nContinue', \
                 description: 'What to do if the distro test fails.')
    string(name: 'TEST_EMAIL_LIST', \
                 defaultValue: 'developers@kalaam.org', \
                 description: 'List of emails to notify with test results.')
  }
  options {
    buildDiscarder(logRotator(numToKeepStr:'30'))
//    disableConcurrentBuilds()
    skipDefaultCheckout true
  }

  stages {

// Build distro from source
    stage('Build') {
      when { not { environment name: 'REPO_BRANCH_OR_TAG', value: 'Use Existing Distro' } }
      steps {
        deleteDir()
        // get source for the requested branch or tag
        sh 'git clone -b ${REPO_BRANCH_OR_TAG} git@bitbucket.org:kamedia/wildfire.git'
        // get and save aegir api scripts for use on aegir servers
        sh 'git clone -b master git@bitbucket.org:kamedia/aegir_api.git'
        stash includes: 'aegir_api/**/*', name: 'AEGIRAPI'

        // do build
        script {
          if (params.REPO_BRANCH_OR_TAG.startsWith('develop') ||
              params.REPO_BRANCH_OR_TAG.startsWith('master')  ||
              params.REPO_BRANCH_OR_TAG.startsWith('release') ||
              params.REPO_BRANCH_OR_TAG.startsWith('maint')  ) {
            env.WF_VERSION = "${REPO_BRANCH_OR_TAG}+${BUILD_NUMBER}"
          } else {
            env.WF_VERSION = "${REPO_BRANCH_OR_TAG}"
          }
          currentBuild.displayName = "wildfire-${env.WF_VERSION}"
          env.DISTRO_URL = "${BUILD_URL}artifact/wildfire-${env.WF_VERSION}${params.PROD_OR_DEV}.tgz"
          sh '''
            cd wildfire
            if [[ -e composer.json ]]; then
              # wildfire version 5
              ./build $WF_VERSION
              echo -n 'qa-w5/qa-smoketest' > scriptvalue
            else
              # wildfire version 4
              if [[ "${REPO_BRANCH_OR_TAG}" == "develop" && "${BUILD_FROM_HEAD}" == "Yes" ]]; then
                mv build-wildfire.make build-wildfire.makeOLD
                grep --invert-match '.download..tag.' build-wildfire.makeOLD > build-wildfire.make
              fi
              /usr/bin/phing -verbose modlist -logger phing.listener.DefaultLogger
              echo -n 'qa-w4/qa-smoketest' > scriptvalue
            fi
          '''
          env.SPECIAL_TESTS_DIR = readFile('wildfire/scriptvalue').trim()
        }
        dir ('wildfire/target') {
          archiveArtifacts artifacts: 'wildfire*.tgz,modulelist*.csv,drushout.txt', followSymlinks: false
        }
      }
    }

// Get distro from a URL instead of building it
    stage('Use Existing Distro') {
      when { environment name: 'REPO_BRANCH_OR_TAG', value: 'Use Existing Distro' }
      steps {
        deleteDir()

        // get and save aegir api scripts for use on aegir servers
        sh 'git clone -b master git@bitbucket.org:kamedia/aegir_api.git'
        stash includes: 'aegir_api/**/*', name: 'AEGIRAPI'

        // get distro URL
        script {
          env.DISTRO_URL = "${env.USE_EXISTING_DISTRO}artifact/${env.USE_EXISTING_DISTRO_NAME}${params.PROD_OR_DEV}.tgz"
          env.SPECIAL_TESTS_DIR = "qa-w5/qa-smoketest"
          currentBuild.displayName = 'Use Distro ' + env.USE_EXISTING_DISTRO_NAME
          echo "Display = " +  currentBuild.displayName
          echo "URL = " + env.DISTRO_URL
        }
      }
    }

// Test distro locally
    stage('Local Test') {
      when { environment name: 'DO_LOCAL_TEST', value: 'Yes' }
      steps {
        echo 'Doing a local test ...'
        script {
          def jobBuild = build job: '../Testing/Wildfire Distro Test', parameters: [ \
              string(name: 'TEST_NAME', value: "${currentBuild.displayName} Local Test"), \
              string(name: 'CODECEPT_OPTIONS', value: "${env.CODECEPT_OPTIONS}"), \
              string(name: 'TEST_LOCATION', value: 'local'), \
              string(name: 'RUN_UNIT', value: params.RUN_UNIT), \
              string(name: 'RUN_MODULE_TESTS', value: params.RUN_MODULE_TESTS), \
              string(name: 'RUN_SPECIAL_TESTS', value: params.RUN_SPECIAL_TESTS), \
              string(name: 'SPECIAL_TESTS_DIR', value: env.SPECIAL_TESTS_DIR), \
              string(name: 'RUN_DRUPAL_TESTS', value: params.RUN_DRUPAL_TESTS), \
              string(name: 'DRUPAL_TEST', value: params.DRUPAL_TEST), \
              string(name: 'DISTRO_URL', value: "${env.DISTRO_URL}"), \
              string(name: 'DBSTATE', value: 'enabled'), \
              string(name: 'FILESTATE', value: 'enabled'), \
              string(name: 'TEST_MODULE', value: "${env.TEST_MODULE}"), \
              string(name: 'TEST_FILE', value: "${env.TEST_FILE}"), \
              string(name: 'SAVE_TEST_OUTPUT', value: "${env.SAVE_TEST_OUTPUT}"), \
              string(name: 'EMAIL_LIST', value: params.TEST_EMAIL_LIST), \
              string(name: 'ERROR_EMAIL_LIST', value: params.TEST_EMAIL_LIST), \
              string(name: 'EMAIL_COMMENT', value: '')], \
              propagate: false
          def jobResult = jobBuild.getResult()
          echo "Test result = ${jobResult}"
          currentBuild.result = jobResult
          if (jobResult != "SUCCESS" && params.WHEN_TESTS_FAIL == 'Abort') {
            currentBuild.result = 'FAILURE'
            echo "currentBuild.result = ${currentBuild.result}"
            error "Local Test failed with ${jobResult}"
          }
        }
      }
    }

// Deploy distro to DEV Aegir
    stage('DEV Deploy') {
      when { anyOf { environment name: 'DEV', value: 'Deploy'; environment name: 'DEV', value: 'Deploy and Test and Delete'} }
      agent { label "$DEV_LOCATION && aegir && wildfire" }
      steps {
        script {
          if ("$PROMPT_FOR_DEPLOY" == "Yes") {
            input message: 'What next?', ok: 'Deploy to DEV'
          }
          if ("$DEV_LOCATION" == "da4") {
            env.SITE_NAME = "aegir-test-${BUILD_NUMBER}.dev4.corp.wildfireserver.net"
          }
          if ("$DEV_LOCATION" == "da5") {
            env.SITE_NAME = "aegir-test-${BUILD_NUMBER}.dev5.corp.wildfireserver.net"
          }
          if ("$DEV_LOCATION" == "da2") {
            env.SITE_NAME = "aegir-test-${BUILD_NUMBER}.dev2.corp.wildfireserver.net"
          }
        }
        echo 'Deploying to DEV...'
        deleteDir()
        unstash 'AEGIRAPI'
        sh '''#!/bin/bash
          ## add platform
          platform=$(aegir_api/create-platform-name ${DEV_LOCATION} ${DISTRO_URL})
          aegir_api/add-platform ${DEV_LOCATION} ${DISTRO_URL} ${platform}
          if [[ "${DEV}" == "Deploy and Test and Delete" ]]; then
            ## add site
            #TODO: may want to put sleep into api for add platform
            sleep 5m
            aegir_api/add-site ${DEV_LOCATION} ${platform} ${SITE_NAME}
            aegir_api/set-admin-password ${platform} ${SITE_NAME}
            ##TODO: adjust this time, give everything a chance to complete
            sleep 5m
          fi
        '''
      }
    }

// Test distro on DEV Aegir
    stage('DEV Test') {
      when { environment name: 'DEV', value: 'Deploy and Test and Delete' }
      steps {
        echo 'Doing a DEV test ...'
        deleteDir()
        unstash 'AEGIRAPI'
        script {
          sh '''
            platform=$(aegir_api/create-platform-name ${DEV_LOCATION} ${DISTRO_URL})
            echo -n ${platform} > scriptvalue
            source aegir_api/local-functions
            echo -n $(lf_database_name ${SITE_NAME}) > scriptvalue-database
          '''
          def dev_platform = readFile('scriptvalue').trim()
          def remote_db_name = readFile('scriptvalue-database').trim()
          if ("$DEV_LOCATION" == "da4") {
            remote_db_url = 'dev-aegir-04.fsn2.corp.wildfireserver.net'
            remote_db_user_pw = 'Dochi7ZahMaep0'
            remote_files_userhost = 'testbot@dev-aegir-04.fsn2.corp.wildfireserver.net'
          }
          if ("$DEV_LOCATION" == "da5") {
            remote_db_url = 'dev-aegir-05.fsn2.corp.wildfireserver.net'
            remote_db_user_pw = 'AdWoovPyctyan0'
            remote_files_userhost = 'testbot@dev-aegir-05.fsn2.corp.wildfireserver.net'
          }
          if ("$DEV_LOCATION" == "da2") {
            remote_db_url = 'dev-aegir-02.fsn2.corp.wildfireserver.net'
            remote_db_user_pw = 'GedaShecsyefAl'
            remote_files_userhost = 'testbot@dev-aegir-02.fsn2.corp.wildfireserver.net'
          }
          echo "remote_db_url = ${remote_db_url}"
          def jobBuild = build job: '../Testing/Wildfire Distro Test', parameters: [ \
              string(name: 'TEST_NAME', value: "${currentBuild.displayName} Aegir Test"), \
              string(name: 'CODECEPT_OPTIONS', value: "${env.CODECEPT_OPTIONS}"), \
              string(name: 'TEST_LOCATION', value: 'remote'), \
              string(name: 'RUN_UNIT', value: params.RUN_UNIT), \
              string(name: 'RUN_MODULE_TESTS', value: params.RUN_MODULE_TESTS), \
              string(name: 'RUN_SPECIAL_TESTS', value: params.RUN_SPECIAL_TESTS), \
              string(name: 'SPECIAL_TESTS_DIR', value: env.SPECIAL_TESTS_DIR), \
              string(name: 'RUN_DRUPAL_TESTS', value: params.RUN_DRUPAL_TESTS), \
              string(name: 'DRUPAL_TEST', value: params.DRUPAL_TEST), \
              string(name: 'DISTRO_URL', value: "${env.DISTRO_URL}"), \
              string(name: 'DBSTATE', value: 'enabled'), \
              string(name: 'FILESTATE', value: 'enabled'), \
              string(name: 'REMOTE_URL', value: "http://${env.SITE_NAME}"), \
              string(name: 'REMOTE_DB_URL', value: "${remote_db_url}"), \
              string(name: 'REMOTE_DB_USER', value: 'aegir_root'), \
              string(name: 'REMOTE_DB_USER_PW', value: "${remote_db_user_pw}"), \
              string(name: 'REMOTE_DB_NAME', value: "${remote_db_name}"), \
              string(name: 'REMOTE_FILES_PLATFORM', value: "${dev_platform}"), \
              string(name: 'REMOTE_FILES_USERHOST', value: "${remote_files_userhost}"), \
              string(name: 'TEST_MODULE', value: "${env.TEST_MODULE}"), \
              string(name: 'TEST_FILE', value: "${env.TEST_FILE}"), \
              string(name: 'SAVE_TEST_OUTPUT', value: "${env.SAVE_TEST_OUTPUT}"), \
              string(name: 'EMAIL_LIST', value: params.TEST_EMAIL_LIST), \
              string(name: 'ERROR_EMAIL_LIST', value: params.TEST_EMAIL_LIST), \
              string(name: 'EMAIL_COMMENT', value: '')], \
              propagate: false
          def jobResult = jobBuild.getResult()
          echo "Test result = ${jobResult}"
          currentBuild.result = jobResult
          env.DEV_TEST_RESULT = jobResult
        }
      }
    }

// Delete distro and site from DEV Aegir
    stage('DEV Delete') {
      when { environment name: 'DEV', value: 'Deploy and Test and Delete'}
      agent { label "$DEV_LOCATION && aegir && wildfire" }
      steps {
        echo 'Deleting from DEV...'
        deleteDir()
        unstash 'AEGIRAPI'
        sh '''#!/bin/bash
          ## delete site
          aegir_api/delete-site ${DEV_LOCATION} ${SITE_NAME}
          ## delete platform
          platform=$(aegir_api/create-platform-name ${DEV_LOCATION} ${DISTRO_URL})
          aegir_api/delete-platform ${DEV_LOCATION} ${platform}
        '''
        script {
          if (env.DEV_TEST_RESULT != "SUCCESS" && params.WHEN_TESTS_FAIL == 'Abort') {
            currentBuild.result = 'FAILURE'
            error "Aegir Test failed with ${env.DEV_TEST_RESULT}"
          }
        }
      }
    }

  }

  post {
    always {
      echo 'always...'
    }
    success {
      echo 'success...'
//      mail to: "${EMAIL_LIST}",
//           subject: "SUCCESS: ${TEST_NAME}",
//           body: "See ${BUILD_URL}testReport for test results. ${EMAIL_COMMENT}"
    }
    unstable {
      echo 'unstable...'
//      mail to: "${EMAIL_LIST}",
//           subject: "FAILURE: ${TEST_NAME}",
//           body: "See ${BUILD_URL}testReport for test results. ${EMAIL_COMMENT}"
    }
    failure {
      echo 'failure...'
      sh 'cat wildfire/target/drushout.txt'
      mail to: "${TEST_EMAIL_LIST}",
           subject: "ERRORS: Build ${currentBuild.displayName}",
           body: "See ${BUILD_URL} for build with errors."
    }
    changed {
      echo 'Something changed...'
    }

  }

}
