/*
 * Copyright 2018 LinkedIn Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

buildscript {
    repositories {
        mavenCentral()
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath 'com.cinnober.gradle:semver-git:2.2.3'
        classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.14'
    }
}

plugins {
    id 'com.gradle.build-scan' version '1.9'
    id 'com.github.kt3k.coveralls' version '2.6.3'
    id 'jacoco'
}

buildScan {
    licenseAgreementUrl = 'https://gradle.com/terms-of-service'
    licenseAgree = 'yes'
}

apply plugin: 'com.cinnober.gradle.semver-git'

apply plugin: 'compare-gradle-builds'

compareGradleBuilds {
    targetBuild.gradleVersion = "4.0"
}

allprojects {
    apply plugin: 'jacoco'

    repositories {
        mavenCentral()
        mavenLocal()
    }
}

ext.versions = [
        hadoop: '2.6.1',
        hive  : '1.1.0',
        pig   : '0.11.0',
        restli: '1.15.7',
        slf4j : '1.7.18',
]

ext.deps = [
        // External dependencies
        assertj             : 'org.assertj:assertj-core:3.8.0',
        awaitility          : 'org.awaitility:awaitility:3.0.0',
        collections         : 'commons-collections:commons-collections:3.2.2',
        commonsCli          : 'commons-cli:commons-cli:1.3.1',
        commonsLang         : 'commons-lang:commons-lang:2.6',
        commonsCompress     : 'org.apache.commons:commons-compress:1.16.1',
        dbcp2               : 'org.apache.commons:commons-dbcp2:2.1.1',
        dbutils             : 'commons-dbutils:commons-dbutils:1.5',
        fileupload          : 'commons-fileupload:commons-fileupload:1.2.1',
        gson                : 'com.google.code.gson:gson:2.8.1',
        guava               : 'com.google.guava:guava:21.0',
        guice               : 'com.google.inject:guice:4.1.0',
        h2                  : 'com.h2database:h2:1.4.193',
        hadoopAnnotations   : "org.apache.hadoop:hadoop-annotations:" + versions.hadoop,
        hadoopAuth          : "org.apache.hadoop:hadoop-auth:" + versions.hadoop,
        hadoopCommon        : "org.apache.hadoop:hadoop-common:" + versions.hadoop,
        hadoopHdfs          : "org.apache.hadoop:hadoop-hdfs:" + versions.hadoop,
        hadoopMRClientCommon: "org.apache.hadoop:hadoop-mapreduce-client-common:" + versions.hadoop,
        hadoopMRClientCore  : "org.apache.hadoop:hadoop-mapreduce-client-core:" + versions.hadoop,
        hiveCli             : "org.apache.hive:hive-cli:" + versions.hive,
        hiveExecCore        : "org.apache.hive:hive-exec:" + versions.hive + ":core",
        hiveMetastore       : "org.apache.hive:hive-metastore:" + versions.hive,
        httpclient          : 'org.apache.httpcomponents:httpclient:4.5.3',
        io                  : 'commons-io:commons-io:2.4',
        jacksonCoreAsl      : 'org.codehaus.jackson:jackson-core-asl:1.9.5',
        jacksonMapperAsl    : 'org.codehaus.jackson:jackson-mapper-asl:1.9.5',
        jetty               : 'org.mortbay.jetty:jetty:6.1.26',
        jettyUtil           : 'org.mortbay.jetty:jetty-util:6.1.26',
        jexl                : 'org.apache.commons:commons-jexl:2.1.1',
        jodaTime            : 'joda-time:joda-time:2.0',
        jopt                : 'net.sf.jopt-simple:jopt-simple:4.3',
        jsr305              : 'com.google.code.findbugs:jsr305:3.0.2',
        junit               : 'junit:junit:4.12',
        kafkaLog4jAppender  : 'org.apache.kafka:kafka-log4j-appender:0.10.0.0',
        log4j               : 'log4j:log4j:1.2.16',
        mail                : 'javax.mail:mail:1.4.5',
        math3               : 'org.apache.commons:commons-math3:3.0',
        metricsCore         : 'io.dropwizard.metrics:metrics-core:3.1.0',
        metricsJvm          : 'io.dropwizard.metrics:metrics-jvm:3.1.0',
        mockito             : 'org.mockito:mockito-core:2.10.0',
        mongoDriver         : 'org.mongodb:mongo-java-driver:2.14.0',
        mysqlConnector      : 'mysql:mysql-connector-java:5.1.28',
        pig                 : 'org.apache.pig:pig:' + versions.pig,
        parquetAvro         : 'com.twitter:parquet-avro:1.3.2',
        parquetBundle       : 'com.twitter:parquet-hadoop-bundle:1.3.2',
        quartz              : 'org.quartz-scheduler:quartz:2.2.1',
        restliGenerator     : 'com.linkedin.pegasus:generator:' + versions.restli,
        restliServer        : 'com.linkedin.pegasus:restli-server:' + versions.restli,
        restliTools         : 'com.linkedin.pegasus:restli-tools:' + versions.restli,
        slf4j               : 'org.slf4j:slf4j-api:' + versions.slf4j,
        slf4jLog4j          : 'org.slf4j:slf4j-log4j12:' + versions.slf4j,
        sparkCore           : 'org.apache.spark:spark-core_2.10:1.4.0',
        snakeyaml           : 'org.yaml:snakeyaml:1.18',
        velocity            : 'org.apache.velocity:velocity:1.7',
        velocityTools       : 'org.apache.velocity:velocity-tools:2.0',
]

subprojects {
    apply plugin: 'java'
    apply plugin: 'net.ltgt.errorprone'

    // Set the same version for all sub-projects to root project version
    version = rootProject.version

    configurations.errorprone {
        dependencies {
            errorprone 'com.google.errorprone:error_prone_core:2.1.0'
        }
    }

    plugins.withType(JavaPlugin) {
        sourceCompatibility = JavaVersion.VERSION_1_8

        /*
         TODO remove afterEvaluate block
         After Evaluate block was added to do a lazy evaluation. This piece of code gets executed by gradle in the
         configuration phase. However, for some reason the version field was not updated by the LinkedIn build
         infrastructure. Thus, using afterEvaluate to do a lazy evaluation of this code block.
         More specifically afterEvaluate kicks in after the rest of the project is configured

         See: http://stackoverflow.com/questions/16218888/can-gradle-extensions-handle-lazy-evaluation-of-a-property
         See: http://stackoverflow.com/questions/16070567/difference-between-gradles-terms-evaluation-and-execution
         */
        project.afterEvaluate {
            // Set the Title and Version fields in the jar
            jar {
                manifest {
                    attributes(
                            'Implementation-Title': project.name,
                            'Implementation-Version': project.version)
                }
            }
        }

        dependencies {
            compile deps.log4j
            compile deps.guice
            compile deps.slf4j
            runtime deps.slf4jLog4j

            testCompile deps.assertj
            testCompile deps.junit
            testCompile deps.mockito
            testCompile deps.awaitility
        }

        test {
            // Set maxParallelForks to a large number and let gradle to force it to a the
            // max-workers number when needed.
            maxParallelForks = 12
        }
    }

    // Common distribution plugin settings for sub-modules
    plugins.withType(DistributionPlugin) {
        distTar {
            compression = Compression.GZIP
            extension = 'tar.gz'
        }
    }

    /**
     * Terminate compilation if warnings occur.
     */
    tasks.withType(JavaCompile) {
        options.compilerArgs += ["-Werror"]
    }

    /**
     * Print test execution summary when informational logging is enabled.
     */
    test {
        testLogging {
            exceptionFormat = 'full'
            afterSuite { desc, result ->
                if (desc.getParent()) {
                    logger.info desc.getName()
                } else {
                    logger.info "Overall"
                }
                logger.info "  ${result.resultType} (" +
                        "${result.testCount} tests, " +
                        "${result.successfulTestCount} passed, " +
                        "${result.failedTestCount} failed, " +
                        "${result.skippedTestCount} skipped)"
            }
        }
    }
}

/**
 * Gradle wrapper task.
 */
task wrapper(type: Wrapper) {
    distributionType('ALL')
}

if (System.env.TRAVIS == 'true') {
    allprojects {
        tasks.withType(Test) {
            // Reduce the memory pressure on the Travis CI to reduce build failures.
            maxParallelForks = 2
            minHeapSize = '128m'
        }
    }
}

def publishedProjects = subprojects.findAll()

// Aggregate all subproject reports into one.
task jacocoAggregateReport(type: JacocoReport, group: 'Coverage reports') {
    description = 'Generates an aggregate report from all subprojects'

    dependsOn(publishedProjects.test)

    // JacocoReport-type task requires users to specify which classes to be covered
    // See details in
    // https://docs.gradle.org/current/dsl/org.gradle.testing.jacoco.tasks.JacocoReport.html
    sourceDirectories = files(publishedProjects.sourceSets.main.allSource.srcDirs)
    classDirectories = files(publishedProjects.sourceSets.main.output)
    executionData = files(publishedProjects.jacocoTestReport.executionData)

    doFirst {
        executionData = files(executionData.findAll { it.exists() })
    }

    reports {
        html.enabled = true // human readable
        xml.enabled = true // required by coveralls
    }
}

coveralls {
    sourceDirs = publishedProjects.sourceSets.main.allSource.srcDirs.flatten()
    jacocoReportPath = "${buildDir}/reports/jacoco/jacocoAggregateReport/jacocoAggregateReport.xml"
}

tasks.coveralls {
    dependsOn jacocoAggregateReport
}
