#!groovy

pipeline() {
  environment{
    def productAcronym="TAS"
    def productMajorVersion='01'
    def productMinorVersion='00'
    def productRev="${BUILD_NUMBER}"
    def packageVersion="${productAcronym}.${productMajorVersion}.${productMinorVersion}.${productRev}"
    def hcRoom = '3242078'
    def dateString = new Date(currentBuild.startTimeInMillis).format('yyyyMMdd_HHmmss')
    def ARTIFACT_LOCATION = "${WORKSPACE}/artifacts/${dateString}"
    def DIST_OUTPUT_FILENAME=''
    def DIST_OUTPUT_FILE=''
    def lastCommitID=''
    def packageName=''
    def STAGING_DIR='/var/www/html/dev/tas'
    def LATEST_STAGING_LINK="${STAGING_DIR}/latest"
    def index="${WORKSPACE}/src/index.html"
    def PHANTOMJS_CDNURL="${MCCF_PUB_REPO_URL}/npm/sinopia/phantomjs"
    def SASS_BINARY_NAME="linux-x64-48"
    def SASS_BINARY_SITE="${MCCF_PUB_REPO_URL}/npm/sinopia/node-sass"
  }
  agent any
  stages{
    stage('setup'){
      steps{
       // notifyBuild('STARTED',hcRoom)
        sh 'node -v'
        sh 'npm -v'
        sh 'mkdir -p ${ARTIFACT_LOCATION}'

        echo 'npm cache clean'
        sh 'npm cache clean'

        sh 'sudo npm set registry ${NPM_REGISTRY} -g'
        sh 'sudo npm set phantomjs_cdnurl ${PHANTOMJS_CDNURL} -g'
        sh 'sudo npm config delete phantomjs_downloadurl -g'
        sh 'sudo npm set sass_binary_name ${SASS_BINARY_NAME} -g'
        sh 'sudo npm set sass_binary_site ${SASS_BINARY_SITE} -g'

        echo "set progress bars to false"
        sh 'sudo npm set progress=false -g'
        
        echo "get last commit to set final packageVersion"
        script{
          lastCommitID=getLastGitCommit()
          echo "last commit is ${lastCommitID}"
          if(lastCommitID?.trim()){
            packageVersion="${packageVersion}_${lastCommitID}"
          }
          else{
            packageVersion="${packageVersion}_${dateString}"
          }
          echo "final packageVersion for tag ${packageVersion}"
          DIST_OUTPUT_FILENAME="${packageName}_${packageVersion}.tar.gz"
          echo "building for package ${DIST_OUTPUT_FILENAME}"
          echo "updating metadata for ${index}"
          def result=updateIndexMetaData()
          echo "RESULT: ${result}"
        }
      }
    }
    stage('Pre-Build'){
      steps{
        sh 'npm config list'
        
        echo "execute npm install"
        sh 'npm install 2>&1 | tee npm_install.log'

        echo "check npm_install.log for download syntax"
        script{
            def STR_TEST=checkNpmInstallLog()
            if("${STR_TEST}" == "PROCEED"){
                println "${STR_TEST}"
            }
            else{
                currentBuild.result='FAILED'
                error("npm install is trying to download content")
            }
        }
        echo "check dependencies"
        sh 'check-dependencies --verbose | tee npm-check-dependencies.log'
      }
    }
    stage('Pre-BuildTests'){
      steps{
        echo "execute ng test"
        sh 'npm run test'
        echo "TODO: test reporter goes here"
        echo "TODO: Coverage tests will go here when ready"
        echo "TODO: 508Tests tests will go here when ready"
      }
    }
    stage('Build'){
      steps{
        echo "build the project"
        sh 'npm run build'
        script{
          if (fileExists("${WORKSPACE}/dist/index.html")) {
            echo "${WORKSPACE}/dist/index.html created, ready to package"
          } else {
              echo 'FAIL'
          }
        }
      }
    }
    stage('Package'){
      steps{
        echo "package app (${WORKSPACE}/dist/) for distribution"
        script{
          packageName=getPackageName()
          println "${packageName}"
          DIST_OUTPUT_FILE="${WORKSPACE}/${DIST_OUTPUT_FILENAME}"
          println "packaging ${DIST_OUTPUT_FILE}"
          sh "tar czf ${DIST_OUTPUT_FILE} -C ${WORKSPACE}/dist/ ."
          println "verify file exists"
          if (fileExists("${DIST_OUTPUT_FILE}")) {
            println "${DIST_OUTPUT_FILE} created, ready to deploy"
          } else {
              println 'FAIL'
          }
        }
      }
    }
    stage('Stage'){
      steps{
        echo "stage the packaged distribution (${DIST_OUTPUT_FILE}) for package ${packageName}"
        stageLatestArtifact("${DIST_OUTPUT_FILE}")
      }
    }
  }
  post{
    always{
      println "all tasks are completed, collecting environment variables to ${WORKSPACE}/${BUILD_TAG}.log"
      sh 'printenv >> $WORKSPACE/$BUILD_TAG.log'
      println "archiving all logs and artifacts specified"
      archiveArtifacts allowEmptyArchive: true, artifacts: '**/*.log, *.html, *.tar.gz', onlyIfSuccessful: false
      notifyBuild(currentBuild.result,hcRoom)
    }
    success{
      echo 'remove node_modules to conserve space'
      sh 'rm node_modules -rf'
      echo 'check environment to determine if we are doing a git commit of tag / notes'
      script {
        def myENV="${ENV}"
        def subENV=myENV[0..2]
        println "determine action for ${myENV}, (aka ${subENV})"
        switch(subENV.toUpperCase()){
          case "AWS":
            println "AWS environment, tag this build"
            gitTagBuild()
            break
          case "EDE":
            println "local environment, do not commit a git tag"
            break
          default:
            println "local environment, do not commit any tag"
        }
      }
    }
    failure{
      echo 'send failure email, this may be removed in the future, certainly needs refined'
      mail body: "${env.JOB_NAME} failed, see ${env.JOB_DISPLAY_URL}",
            from: 'xxxx@yyyyy.com',
            replyTo: 'xxxx@yyyy.com',
            subject: "project build failed for build ${env.BUILD_DISPLAY_NAME} for ${env.JOB_DISPLAY_URL}",
            to: 'yyyyy@yyyy.com'
    }
  }
}

// notifyBuild
// will send color coded notifications to hipchat
//
def notifyBuild(String buildStatus = 'STARTED', String hcRoom = '3242078') {
// build status of null means successful
    buildStatus =  buildStatus ?: 'SUCCESSFUL'

    def hcMessage=gitChangesets()
    def buildURL="${env.BUILD_URL}"
    def lastBuild = currentBuild.getPreviousBuild()

    // Default values
    def color = 'RED'
    def colorCode = '#FF0000'
    def subject = "${buildStatus}: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'"
    def summary = "${subject} (${env.BUILD_URL})"
    def details = """<p>STARTED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':</p>
     <p>Check console output at "<a href="${env.BUILD_URL}">${env.JOB_NAME} [${env.BUILD_NUMBER}]</a>"</p>"""

    // Override default values based on build status
    if (buildStatus == 'STARTED') {
      color = 'YELLOW'
      colorCode = '#FFFF00'
    } else if (buildStatus == 'SUCCESSFUL') {
      color = 'GREEN'
      colorCode = '#00FF00'
      if( lastBuild && lastBuild.getResult().toString()=="FAILURE" ){
        buildStatus = 'FIXED'
      }
    } else if (buildStatus == 'ABORTED') {
      color = 'PURPLE'
      colorCode = '#800080'
    } else if (buildStatus == 'UNSTABLE') {
      color = 'GRAY'
      colorCode = '#808080'
    }  else {
      color = 'RED'
      colorCode = '#FF0000'
    }
 
   // Send notifications
    println "send notice of ${buildStatus} to hipchat room: ${hcRoom}"
    println "check value of host (${buildURL})"
    if(buildURL.toLowerCase().contains("aws")){
      println "we are in AWS, send notice of ${buildStatus} to hipchat room: ${hcRoom}"
      if(buildStatus == 'SUCCESSFUL'){
        println "only send notice if previous build failed"
        if( lastBuild && lastBuild.getResult().toString()=="FAILURE" ){
          println "the previous build ${lastBuild.getId()} failed"
          hipchatSend (
            color: color, 
            credentialId: 'jenkins_hc_notification', 
            message: summary + ": changesets:  " + hcMessage, 
            notify: true, 
            room: hcRoom, 
            sendAs: 'jenkins_build_lee', 
            textFormat: false, 
            v2enabled: true
          )
        }
        else {
          println "the previous build " + lastBuild.getResult().toString()
        }
      }
      else {
        println "this build ${buildStatus}"
        hipchatSend (
            color: color, 
            credentialId: 'jenkins_hc_notification', 
            message: summary + ": changesets:  " + hcMessage, 
            notify: true, 
            room: hcRoom, 
            sendAs: 'jenkins_build_lee', 
            textFormat: false, 
            v2enabled: true
        )
      }
    }
    else {
      println "no hipchat notice to be sent for host ${buildURL}"
    }
}

def gitChangesets(){
    def changeLogSets = currentBuild.changeSets
    println "reviewing changesets:"
    def commitMessage=""
    for (int i = 0; i < changeLogSets.size(); i++) {
        def entries = changeLogSets[i].items
        for (int j = 0; j < entries.length; j++) {
            def entry = entries[j]
            commitMessage="${commitMessage} \n ${entry.commitId} by ${entry.author} on ${new Date(entry.timestamp)}"
            echo "${entry.commitId} by ${entry.author} on ${new Date(entry.timestamp)}: ${entry.msg}"
            def files = new ArrayList(entry.affectedFiles)
            for (int k = 0; k < files.size(); k++) {
                def file = files[k]
                echo "  ${file.editType.name} ${file.path}"
            }
        }
    }
    return "${commitMessage}"
}

def getPackageName(){
  println "getting package name"
  def MYNAME
  MYNAME = sh (
      script: 'npm run env | grep npm_package_name | cut -d \"=\" -f 2',
      returnStdout: true
    ).trim()
  MYNAME
}

def stageLatestArtifact(artifact){
    println "stage the latest build artifact(${artifact}) for release"
    def artifact_name= artifact.tokenize('/').last()
    def staging = "${STAGING_DIR}"
    def latest = "${LATEST_STAGING_LINK}"
    try {
        println "check ${staging} directory exist"
        sh "[[ -d ${staging} ]] || sudo mkdir -p ${staging}"
        println "copy ${artifact} to ${staging}/"
        sh "sudo cp ${artifact} ${staging}/"
        println "create symbolic link to staged artifact"
        sh "sudo ln -sfn ${staging}/${artifact_name} ${latest}"
        println "verify link created"
        def linkExists=sh (
            script: "readlink ${latest}",
            returnStdout: true
            ).trim()
        sh """
            if [[ -n "${linkExists}" ]]; then
                echo "link exists for ${latest}"
            else
                echo "link not found ${latest}"
            fi
        """
    } catch(Exception e){
        println "something bad happened while staging artifact, throw and fail"
        println e.toString()
        throw e
    }
}

def getLastGitCommit(){
  println "getting last git commit"
  def LAST_COMMIT
  LAST_COMMIT = sh (
    script: 'git log -n 1 $BRANCH_NAME --pretty=format:"%H"',
    returnStdout: true
  ).trim()
  LAST_COMMIT[0..6]
}

def getHostname(){
  def THISHOSTNAME
  if(isUnix()){
    THISHOSTNAME = sh (
      script: 'hostname',
      returnStdout: true
    ).trim()
  }
  else {
    THISHOSTNAME = bat (
      script: 'hostname',
      returnStdout: true
    ).trim()
  }
  THISHOSTNAME
}

def gitTagBuild(){
  def MYHOSTNAME=getHostname()
  def commit_message = /"jenkins-${JOB_BASE_NAME}-${BUILD_NUMBER}-${MYHOSTNAME}"/
  echo "set the user.name"
  sh 'git config user.name "lbenhart"'
  echo "set the user.email"
  def uEmail = /"lee.benhart@halfaker.com"/ 
  sh """
    git config user.email ${uEmail}
  """
  sh 'git config alias.versionlog "notes --ref=versionlog append"'
  sh """git config --add remote.origin.push '+refs/notes/*:refs/notes/*'"""
  sh """git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*'"""
  sh 'cat .git/config'
  echo "append version note to this commit"
  addGitVersionLog()
  echo "tag this commit"
  sh """
    git tag -a ${packageVersion} -m '${commit_message}' ${lastCommitID}
  """
  echo "push changes to remote"
  sh 'git config push.default simple'
  sh 'git push origin HEAD:master --tags'
}

@NonCPS
def updateIndexMetaData(){
  def lastBuildDate=new Date(currentBuild.startTimeInMillis).format('MMM dd, yyyy hh:mm:ss Z')
  metaData=["distributionFileName":"${DIST_OUTPUT_FILENAME}", "lastBuildDate":"${lastBuildDate}", "version":"${packageVersion}" ]
  metaData.each { name, content -> 
     println "update meta tag name=\"${name}\", content=\"${content}\""
     sh """
       sed -i '/<head>/a <meta name=\"${name}\" content=\"${content}\" >' "${index}"
     """
  }
}

def addGitVersionLog(){
  def lastBuildDate=new Date(currentBuild.startTimeInMillis).format('MMM dd, yyyy hh:mm:ss Z')
  def versionString="version: ${packageVersion}"
  def buildDateString="lastBuildDate: ${lastBuildDate}"
  def distributionString="distributionFileName: <staging_url>/${DIST_OUTPUT_FILENAME}"
  sh """
    git versionlog ${lastCommitID} -m "${versionString}, ${buildDateString}, ${distributionString}"
  """
}

def checkNpmInstallLog(){
  println "checking npm install log for 'Downloading.*github'"
  def MYRESULT
  MYRESULT = sh (
      script: """
        if grep -Exq "Downloading.*github" npm_install.log
        then
          echo "ERROR: unauthorized download"
        else
          echo "PROCEED"
        fi
        """,
      returnStdout: true
    ).trim()
  println "returning ${MYRESULT}"
  return MYRESULT
}