import org.pmiops.workbench.tooling.GenerateAPIListingTask

// Runs before all tasks. Sets up properties and dependencies for the build
// process itself.
buildscript {
    // keep in sync with:
    // the runtime field in api/src/main/webapp/WEB-INF/appengine-web.xml.template
    // the Docker image in ci/Dockerfile.circle_build
    // the Docker image in deploy/Dockerfile
    // in this file:
    // * sourceCompatibility
    // * targetCompatibility
    if (JavaVersion.current() != JavaVersion.VERSION_17) {
        throw new GradleException(
                "This build must be run with Java 17. " +
                        "See developer-system-initialization.md. " +
                        "The java version used was ${JavaVersion.current()}.")
    }

    // External properties on the default project. Values declared in ext blocks
    // outside of the buildscript block aren't usable here.
    ext {
        // Note: Spring versions are handled by plugins.
        // See the plugins and dependencyManagement blocks below.

        GAE_VERSION = '2.0.36'
        GOOGLE_AUTH_LIBRARY_VERSION = '1.35.0'
        GSON_VERSION = '2.13.1'
        HIBERNATE_VERSION = '6.5.3.Final'
        JACKSON_VERSION = '2.18.3'
        LIQUIBASE_VERSION = '4.31.1'
        // 1.5.7+ results in a runtime error:
        // Logging system failed to initialize using configuration from 'null'
        //  java.lang.NoSuchMethodError: 'java.lang.Object ch.qos.logback.classic.LoggerContext.getConfigurationLock()'
        LOGBACK_VERSION = '1.5.6'
        MAPSTRUCT_VERSION = '1.6.2'
        OKHTTP_VERSION = '4.12.0'
        OPENTELEMETRY_SDK_VERSION = '1.48.0'
        OPENTELEMETRY_JAVA_VERSION = '2.16.0'
        OPENTELEMETRY_GOOGLE_VERSION = '0.34.0'
        PROTOBUF_VERSION = '4.31.0'
        SPRINGFOX_VERSION = '3.0.0'
        SWAGGER_VERSION = '2.2.29'
    }

    repositories {
        mavenCentral()
    }
}

plugins {
    id 'eclipse'
    id 'idea'
    id 'java'
    id 'war'

    id 'io.spring.dependency-management' version '1.1.7'
    // keep in sync with the dependencyManagement block below
    id 'org.springframework.boot' version '3.2.12'

    id 'com.diffplug.spotless' version '6.23.3'
    id 'com.google.cloud.tools.appengine-appenginewebxml' version '2.8.0'
    id 'com.google.cloud.tools.jib' version '3.4.2'

    // required even though we have removed our own Kotlin code - transitive dependency?
    id 'org.jetbrains.kotlin.jvm' version '1.9.25'

    // Note: if you plan to upgrade the version of swagger-codegen beyond 2.2.3, be aware of two
    // implicit dependencies: (1) the set of "generatedCompile" Gradle dependencies need to be updated
    // to match the modules imported by the Swagger codegen templates, and (2) some template files
    // are overridden with forked templates within this repo; they will likely need to be re-copied from
    // the newer release version and have AoU-specific modifications re-applied.
    id 'org.hidetake.swagger.generator' version '2.19.2'
    id 'org.owasp.dependencycheck' version '12.1.0'
    id 'jacoco'
}

// relates to the Spring plugin io.spring.dependency-management
// which has BOM-like properties
dependencyManagement {
    dependencies {
        dependency group: 'org.springframework', name: 'spring-core', version: '6.2.7'
        // keep in sync with the plugin block above
        dependency group: 'org.springframework.boot', name: 'spring-boot', version: '3.2.12'
        dependency group: 'org.springframework.security', name: 'spring-security', version: '6.4.5'
    }
}

if (System.getenv("ADD_XLINT_DEPRECATION")) {
  allprojects {
    gradle.projectsEvaluated {
      tasks.withType(JavaCompile) {
        options.compilerArgs.add("-Xlint:deprecation")
      }
    }
  }
}

if (System.getenv("ADD_XLINT_UNCHECKED")) {
  allprojects {
    gradle.projectsEvaluated {
      tasks.withType(JavaCompile) {
        options.compilerArgs.add("-Xlint:unchecked")
      }
    }
  }
}

// Artifact configurations derived from base configs. Configuration names
// are concatenated by the Java plugin.
// https://docs.gradle.org/current/userguide/java_plugin.html#java_source_set_configurations
configurations {
    __bigQueryTest__Compile.extendsFrom testImplementation
    __bigQueryTest__Runtime.extendsFrom testRuntime

    __integration__Compile.extendsFrom testImplementation
    __integration__Runtime.extendsFrom testRuntime

    __tools__Implementation.extendsFrom implementation
    __tools__RuntimeOnly.extendsFrom runtimeOnly

    __swaggerCodegenV3__

    generatedCompile {
        exclude group: 'com.google.guava', module: 'guava-jdk5'
    }
}

// Shared variables for Swagger codegen. Use "ext" rather than "def" to allow
// access globally, including from within helper functions.
ext.SWAGGER_CODEGEN_BASE_PKG = 'org.pmiops.workbench'
ext.SWAGGER_3_CODEGEN_DIR = "$buildDir/swagger3"

// Raw options passed to the Swagger codegen CLI.
ext.SWAGGER_3_RAW_OPTS = [
        // By default, the ignore file within the output directory is used. Override
        // as we don't track the output directory in source.
        '--ignore-file-override', "$projectDir/.swagger3-codegen-ignore"
]

def swagger3JavaClient(yaml, pkg, rawOptExtras = []) {
    return {
        inputFile = file("src/main/resources/${yaml}")
        code {
            configuration = configurations.__swaggerCodegenV3__
            language = 'java'
            outputDir = file(SWAGGER_3_CODEGEN_DIR)
            templateDir = file("$projectDir/src/main/resources/swagger3codegen")
            // Since the output directory is shared among these swagger tasks, wiping
            // the directory would result in task invalidation / churn.
            wipeOutputDir = false
            rawOptions = [
                    // By default, the ignore file within the output directory is used. Override
                    // as we don't track the output directory in source.
                    '--ignore-file-override', "$projectDir/.swagger3-codegen-ignore"
            ] + rawOptExtras
            additionalProperties = [
                    'sourceFolder'     : '',
                    'library'          : 'okhttp-gson',
                    'serializableModel': 'true',
                    'dateLibrary'      : 'java8',
                    'invokerPackage'   : "${SWAGGER_CODEGEN_BASE_PKG}.${pkg}",
                    'modelPackage'     : "${SWAGGER_CODEGEN_BASE_PKG}.${pkg}.model",
                    'apiPackage'       : "${SWAGGER_CODEGEN_BASE_PKG}.${pkg}.api",
                    'hideGenerationTimestamp': 'true',
                    'jakarta'          : 'true',
            ]
        }
        // Validation only works for Swagger 2 - skip.
        validation {
            inputFile = null
        }
    }
}

// Configuration for the Swagger Gradle plugin:
// https://github.com/int128/gradle-swagger-generator-plugin
//
// Note: The tasks below share an output directory, but we rely on the swagger
// ignore file to ensure they don't step on eachother's outputs. If this were to
// happen in the future due to a regression or a codegen upgrade, the issue
// would likely manifest as an infinite build loop on our continuous incremental
// build (e.g. dev-up). Run ./gradlew copmileGeneratedJava --info to see which
// overlapping files/diretories may be getting written by different Swagger
// codegen tasks.
swaggerSources {
    firecloud swagger3JavaClient("firecloud.yaml", "firecloud", [
            '--model-name-prefix', 'Firecloud'
    ])
    rawls swagger3JavaClient("rawls.yaml", "rawls", [
            '--model-name-prefix', 'Rawls'
    ])
    notebooks swagger3JavaClient("notebooks.yaml", "notebooks")
    jira swagger3JavaClient("jira.yaml", "jira")
    absorb swagger3JavaClient("absorb.yaml", "absorb")
    rdr swagger3JavaClient("rdr.yaml", "rdr", [
            '--model-name-prefix', 'Rdr'
    ])
    captcha swagger3JavaClient("captcha.yaml", "captcha")

    leonardo swagger3JavaClient("leonardo.yaml", "legacy_leonardo_client", [
            '--model-name-prefix', 'Leonardo'
    ])

    calhoun swagger3JavaClient("calhoun.yaml", "calhoun", [
            '--model-name-prefix', 'Calhoun'
    ])
    tanagra swagger3JavaClient("tanagra.yaml", "tanagra")

    wsmanager swagger3JavaClient("ws-manager.yaml", "wsmanager")
    vwbum swagger3JavaClient("vwb-user-manager.yaml", "vwb.user")
    vwbexfil swagger3JavaClient("vwb-exfil-manager.yaml", "vwb.exfil")
    vwbsam swagger3JavaClient("vwb-sam.yaml", "vwb.sam")

    // Workbench needs a special configuration style, as we generate Spring server
    // bindings in this case.
    workbench {
        inputFile = file('src/main/resources/workbench-api.yaml')
        code {
            configuration = configurations.__swaggerCodegenV3__
            language = 'spring'
            outputDir = file(SWAGGER_3_CODEGEN_DIR)
            templateDir = file("$projectDir/src/main/resources/swagger3codegen")
            wipeOutputDir = false
            rawOptions = SWAGGER_3_RAW_OPTS
            additionalProperties = [
                    'sourceFolder'   : '',
                    'modelPackage'   : "${SWAGGER_CODEGEN_BASE_PKG}.model",
                    'apiPackage'     : "${SWAGGER_CODEGEN_BASE_PKG}.api",
                    'useTags'        : 'true',
                    // Generates delegate interfaces; used to make method annotations work without
                    // having to copy them to our implementations.
                    'delegatePattern': 'true',
                    'dateLibrary'    : 'java8',
                    'hideGenerationTimestamp': 'true',
                    'jakarta'          : 'true',
            ]
        }
    }
}

//
// AppEngine
//

// Generate AppEngine Cron file
def workbenchEnv = System.getenv('WORKBENCH_ENV') != null ? System.getenv('WORKBENCH_ENV') : 'local'
task generate_appengine_cron_yaml(type: Exec) {
    executable "ruby"
    args = ["libproject/generate_appengine_cron_yaml.rb", workbenchEnv]
}

// Generate AppEngine Web Configration XML file
task generate_appengine_web_xml(type: Exec) {
    executable "ruby"
    args "libproject/generate_appengine_web_xml.rb"
}


// Spotless code linter plugin settings
spotless {
    java {
        googleJavaFormat()
        target fileTree('.') {
            include '**/*.java'

            exclude 'src/generated/**'
            exclude 'build/**'
        }
    }
}

test {
    useJUnitPlatform()
    // Unit testing time is cut roughly in half by running them in parallel. We avoid this on
    // Circle because they are already split apart using a different algorithm.
    maxParallelForks = System.getenv('CIRCLECI') == 'true' ? 1 :
      Runtime.runtime.availableProcessors().intdiv(2) ?: 1
}

jacoco {
    toolVersion = "0.8.10"
}

jacocoTestReport {
    getExecutionData().setFrom(fileTree(buildDir).include("/jacoco/*.exec"))
    reports {
        xml.enabled = true
    }
}

// The plugin generates configuration names by concatenating SourceSet names
// with builtin identifiers according to the rules at
// https://docs.gradle.org/current/userguide/java_plugin.html#java_source_set_tasks
sourceSets {
    //
    // SorceSets added by Java plugin. These share a namespace with the ones users create.
    //
    generated {
        compileClasspath = configurations.generatedCompileClasspath
        java {
            srcDir SWAGGER_3_CODEGEN_DIR
        }
    }
    main {
        compileClasspath += generated.output
        runtimeClasspath += generated.output
    }
    test {
        // Allow unit tests to directly load config files.
        resources {
            srcDir "config/"
        }
        compileClasspath += generated.output
        runtimeClasspath += generated.output
    }

    //
    // Custom SourceSets
    //
    // Here we use a naming convention with __ word boundaries at start and end
    // to avoid confusion. For example, the plugin may define a __tools__Compile configuration
    // or a compile__tools__Java task. This approach makes it more obvious where there's
    // a dynamically defined symbol name, so usages stick out and it's easier to identify the
    // constituent parts.
    // https://docs.gradle.org/current/userguide/java_plugin.html#java_source_set_tasks
    // https://docs.gradle.org/current/userguide/java_plugin.html#java_source_set_configurations
    //

    // BigQuery testing sources
    __bigQueryTest__ {
        resources {
            srcDir "bigquerytest/resources"
            srcDir "config/"
            include "bigquery/**"
            include "cdm/**"
        }
        java {
            compileClasspath += main.output + test.output + generated.output
            runtimeClasspath += main.output + test.output + generated.output
            srcDir file('src/bigquerytest/java')
        }
    }

    // Integration testing sources
    __integration__ {
        resources {
            srcDir "config/"
        }
        java {
            compileClasspath += main.output + generated.output
            runtimeClasspath += main.output + generated.output
            srcDir file('src/integration/java')
        }
    }

    // AoU Tools sources
    __tools__ {
        compileClasspath += main.output + generated.output
        runtimeClasspath += main.output + generated.output

        resources {
            srcDir "tools/src/main/resources"
        }
        java {
            srcDirs = ['tools/src/main/java']
        }
    }
}

// Add dependencies to the classes builtin task from the  Java plugin.
// "This is an aggregate task that just depends on other tasks.
// Other plugins may attach additional compilation tasks to it."
// https://docs.gradle.org/current/userguide/java_plugin.html
classes.dependsOn 'generatedClasses'

// https://docs.gradle.org/current/userguide/idea_plugin.html
project.tasks.ideaModule.dependsOn(generateSwaggerCode)

// Java plugin's Generated Source Set gives us the compileGeneratedJava task.
// We need to provide it with the swagger-codegen tasks that output Java; this
// task is defined by the Swagger gradle plugin, and includes all registered
// Swagger sources, per the swaggerSources tuple above.
project.tasks.compileGeneratedJava.dependsOn(generateSwaggerCode)

project.tasks.bootWar.dependsOn(['compileGeneratedJava', 'generate_appengine_web_xml',
                                 'generate_appengine_cron_yaml'])

// Clear out generated Java sorces before cleaning the project.
clean.doFirst {
    delete(SWAGGER_3_CODEGEN_DIR)
}

repositories {
    maven {
        // for Terra service clients (currently sam-client and leonardo-client)
        url 'https://us-central1-maven.pkg.dev/dsp-artifact-registry/libs-release/'
    }
    mavenCentral()
}

// To show the dependency tree, try: ./project.rb gradle dependencies --configuration compile
dependencies {
    annotationProcessor "org.mapstruct:mapstruct-processor:$project.ext.MAPSTRUCT_VERSION"

    // 3.0.57+ results in runtime errors because it adds @NotNull annotations by default:
    // https://github.com/swagger-api/swagger-codegen-generators/issues/1295
    // 3.0.62+ results in compilation errors:
    // package org.openapitools.jackson.nullable does not exist
    // package io.swagger.configuration does not exist
    __swaggerCodegenV3__ "io.swagger.codegen.v3:swagger-codegen-cli:3.0.56"


    // Spring versions are set by the dependency management plugin.
    // See the plugins and dependencyManagement blocks above.

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-tomcat'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.retry:spring-retry'
    implementation 'org.springframework.security:spring-security-core'
    implementation 'org.springframework.security:spring-security-crypto'
    implementation 'org.springframework.security:spring-security-web'
    implementation 'org.springframework:spring-aop'
    implementation 'org.springframework:spring-aspects'
    implementation 'org.springframework:spring-beans'
    implementation 'org.springframework:spring-context'
    implementation 'org.springframework:spring-core'
    implementation 'org.springframework:spring-expression'
    implementation 'org.springframework:spring-jcl'
    implementation 'org.springframework:spring-jdbc'
    implementation 'org.springframework:spring-orm'
    implementation 'org.springframework:spring-test'
    implementation 'org.springframework:spring-tx'
    implementation 'org.springframework:spring-web'
    implementation 'org.springframework:spring-webmvc'



    implementation "ch.qos.logback:logback-classic:$project.ext.LOGBACK_VERSION"
    implementation "ch.qos.logback:logback-core:$project.ext.LOGBACK_VERSION"
    implementation "com.fasterxml.jackson.core:jackson-annotations:$project.ext.JACKSON_VERSION"
    implementation "com.fasterxml.jackson.core:jackson-core:$project.ext.JACKSON_VERSION"
    implementation "com.fasterxml.jackson.core:jackson-databind:$project.ext.JACKSON_VERSION"
    implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$project.ext.JACKSON_VERSION"
    implementation "com.github.java-json-tools:json-patch:1.13"
    implementation 'org.javers:javers-core:7.7.0'
    implementation "com.squareup.okhttp3:logging-interceptor:$project.ext.OKHTTP_VERSION"
    implementation "com.squareup.okhttp3:okhttp:$project.ext.OKHTTP_VERSION"

    implementation "io.opentelemetry:opentelemetry-api:$project.ext.OPENTELEMETRY_SDK_VERSION"
    implementation "io.opentelemetry:opentelemetry-context:$project.ext.OPENTELEMETRY_SDK_VERSION"
    implementation "io.opentelemetry:opentelemetry-exporter-otlp:$project.ext.OPENTELEMETRY_SDK_VERSION"
    implementation "io.opentelemetry:opentelemetry-sdk:$project.ext.OPENTELEMETRY_SDK_VERSION"
    implementation "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:$project.ext.OPENTELEMETRY_SDK_VERSION"
    implementation "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:$project.ext.OPENTELEMETRY_SDK_VERSION"
    implementation "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:$project.ext.OPENTELEMETRY_JAVA_VERSION"
    implementation "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:$project.ext.OPENTELEMETRY_JAVA_VERSION"
    implementation("com.google.cloud.opentelemetry:exporter-trace:$project.ext.OPENTELEMETRY_GOOGLE_VERSION") {
        exclude group: 'com.google.cloud', module: 'libraries-bom'
        exclude group: 'com.google.cloud', module: 'google-cloud-core'
        exclude group: 'com.google.cloud', module: 'google-cloud-trace'
    }
    implementation("com.google.cloud.opentelemetry:exporter-metrics:$project.ext.OPENTELEMETRY_GOOGLE_VERSION") {
        exclude group: 'com.google.cloud', module: 'libraries-bom'
        exclude group: 'com.google.cloud', module: 'google-cloud-core'
        exclude group: 'com.google.cloud', module: 'google-cloud-trace'
    }
    implementation "com.google.cloud.opentelemetry:exporter-auto:$project.ext.OPENTELEMETRY_GOOGLE_VERSION-alpha"

    implementation "org.liquibase:liquibase-core:$project.ext.LIQUIBASE_VERSION"
    implementation 'com.mysql:mysql-connector-j:9.3.0'
    implementation "org.apache.commons:commons-collections4:4.5.0-M3"
    implementation 'org.apache.commons:commons-lang3:3.18.0'
    implementation 'org.apache.commons:commons-text:1.13.1'
    // 5.4+ results in a runtime error:
    // java.lang.NoSuchMethodError: 'void org.apache.hc.core5.http.impl.io.DefaultHttpRequestWriterFactory.<init>(org.apache.hc.core5.http.config.Http1Config)'
    implementation "org.apache.httpcomponents.client5:httpclient5:5.3.1"
    implementation 'commons-codec:commons-codec:1.17.0'
    implementation 'com.auth0:java-jwt:4.5.0'
    implementation 'org.json:json:20250107'

    implementation 'com.sendgrid:sendgrid-java:4.10.3'
    // Assure compatible dependencies by using Bills of Materials (BOMs)
    // https://cloud.google.com/java/docs/bom

    implementation platform('com.google.cloud:google-cloud-bom:0.241.0')
    implementation platform('com.google.cloud:libraries-bom:26.60.0')

    // do not specify versions for these dependencies, because they are set by the BOM

    implementation 'com.google.cloud:google-cloud-bigquery'
    implementation 'com.google.cloud:google-cloud-iamcredentials'
    implementation 'com.google.cloud:google-cloud-logging'
    implementation 'com.google.cloud:google-cloud-monitoring'
    implementation 'com.google.cloud:google-cloud-trace'
    implementation 'com.google.cloud:google-cloud-storage'
    implementation 'com.google.cloud:google-cloud-tasks'

    implementation("com.google.appengine:appengine-api-1.0-sdk:$project.ext.GAE_VERSION") {
        exclude group: 'com.google.api-client', module: 'google-api-client-servlet'
    }
    implementation 'com.google.apis:google-api-services-admin-directory:directory_v1-rev20250513-2.0.0'
    implementation 'com.google.apis:google-api-services-cloudbilling:v1-rev20241011-2.0.0'
    implementation 'com.google.apis:google-api-services-cloudresourcemanager:v3-rev20250508-2.0.0'
    implementation 'com.google.apis:google-api-services-oauth2:v2-rev20200213-2.0.0'
    implementation 'com.google.apis:google-api-services-iam:v1-rev20241114-2.0.0'
    implementation 'com.google.api-client:google-api-client-appengine:2.7.1'
    implementation "com.google.auth:google-auth-library-appengine:$project.ext.GOOGLE_AUTH_LIBRARY_VERSION"
    implementation "com.google.auth:google-auth-library-oauth2-http:$project.ext.GOOGLE_AUTH_LIBRARY_VERSION"
    // 1.11.2+ results in a compilation error:
    //    > Could not find com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.11.1-SNAPSHOT.
    //     Required by:
    //         project : > com.google.cloud.sql:mysql-socket-factory:1.11.2
    implementation 'com.google.cloud.sql:mysql-socket-factory:1.11.1'
    implementation "com.google.code.gson:gson:$project.ext.GSON_VERSION"
    implementation 'com.google.oauth-client:google-oauth-client-jetty:1.37.0'

    implementation "com.google.protobuf:protobuf-java:$project.ext.PROTOBUF_VERSION"
    implementation "com.google.protobuf:protobuf-java-util:$project.ext.PROTOBUF_VERSION"

    implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'

    implementation "org.hibernate.orm:hibernate-core:$project.ext.HIBERNATE_VERSION"
    implementation "org.hibernate.orm:hibernate-community-dialects:$project.ext.HIBERNATE_VERSION"

    implementation('org.apache.tomcat:tomcat-jdbc:11.0.5')





    // updated versions of transitive dependencies to resolve vulnerabilities

    // https://security.snyk.io/vuln/SNYK-JAVA-ORGBOUNCYCASTLE-6612984
    // https://security.snyk.io/vuln/SNYK-JAVA-ORGBOUNCYCASTLE-6613076
    // https://security.snyk.io/vuln/SNYK-JAVA-ORGBOUNCYCASTLE-6613079
    implementation 'org.bouncycastle:bcprov-jdk18on:1.79'

    // https://www.cve.org/CVERecord?id=CVE-2023-2976
    implementation 'com.google.guava:guava:33.4.0-jre'


    implementation "org.mapstruct:mapstruct:$project.ext.MAPSTRUCT_VERSION"
    testAnnotationProcessor "org.mapstruct:mapstruct-processor:$project.ext.MAPSTRUCT_VERSION"

    // updated 13 Dec 2023 to most recent passing Sam on 13 Dec
    implementation("org.broadinstitute.dsde.workbench:sam-client_2.13:0.1-c0263cf") {
      exclude group: 'org.apache.oltu.oauth2', module: 'org.apache.oltu.oauth2.common'
    }

    // updated 2 Oct 2024 to most recent develop
    // see https://github.com/DataBiosphere/leonardo/actions/workflows/publish_java_client.yml
    implementation("org.broadinstitute.dsde.workbench:leonardo-client_2.13:1.3.6-3fbffee")

    implementation group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '4.0.5'

    // transitive dependencies called out by libyears

    implementation "org.jetbrains:annotations:26.0.2"
    implementation "commons-logging:commons-logging:1.3.5"

    // jakarta
    implementation 'jakarta.activation:jakarta.activation-api:2.1.3'
    implementation 'jakarta.annotation:jakarta.annotation-api:3.0.0'
    implementation 'jakarta.inject:jakarta.inject-api:2.0.1'
    implementation 'jakarta.mail:jakarta.mail-api:2.1.3'
    // upgrading to 3.2.0 causes an error
    // Error creating bean with name 'entityManagerFactory' defined in class path resource
    // [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: EntityManagerFactory
    // interface [interface org.hibernate.SessionFactory] seems to conflict with Spring's EntityManagerFactoryInfo
    // mixin - consider resetting the 'entityManagerFactoryInterface' property to plain
    // [jakarta.persistence.EntityManagerFactory]
    // https://github.com/spring-projects/spring-boot/issues/39753
    implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'
    implementation 'jakarta.servlet:jakarta.servlet-api:6.1.0'
    implementation 'jakarta.validation:jakarta.validation-api:3.1.1'
    implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.2'

    generatedCompile 'jakarta.annotation:jakarta.annotation-api:3.0.0'
    generatedCompile 'jakarta.inject:jakarta.inject-api:2.0.1'
    generatedCompile 'jakarta.mail:jakarta.mail-api:2.1.3'
    generatedCompile 'jakarta.persistence:jakarta.persistence-api:3.1.0'
    generatedCompile 'jakarta.servlet:jakarta.servlet-api:6.1.0'
    generatedCompile 'jakarta.validation:jakarta.validation-api:3.1.1'
    generatedCompile 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.2'

    // Dependencies for Swagger codegen-generated sources. This should include all dependencies required by Swagger's
    // default okhttp API codegen templates (see https://github.com/swagger-api/swagger-codegen/blob/v2.2.3/samples/client/petstore/spring-stubs/pom.xml)
    // plus any custom templates included in our repo under the SWAGGER_2_TEMPLATE_DIR.
    generatedCompile 'org.springframework.boot:spring-boot-starter-data-rest'
    generatedCompile 'org.springframework.boot:spring-boot-starter-validation'
    generatedCompile "io.springfox:springfox-swagger-ui:$project.ext.SPRINGFOX_VERSION"
    generatedCompile "com.squareup.okhttp3:okhttp:$project.ext.OKHTTP_VERSION"
    generatedCompile "com.squareup.okhttp3:logging-interceptor:$project.ext.OKHTTP_VERSION"
    generatedCompile "com.google.code.gson:gson:$project.ext.GSON_VERSION"
    // OpenTelemetry is an AoU-specific addition to the default Swagger API dependencies. See the
    // template file api.mustache for more details.
    generatedCompile "io.opentelemetry:opentelemetry-api:$project.ext.OPENTELEMETRY_SDK_VERSION"
    generatedCompile "io.opentelemetry:opentelemetry-context:$project.ext.OPENTELEMETRY_SDK_VERSION"

    // Swagger3 codegen deps
    // TODO(calbach): The duplicated deps here are highly suspect. Investigate
    // removing the generated sourceSet, or else fixing the runtime deps.
    implementation "io.swagger.core.v3:swagger-annotations:$project.ext.SWAGGER_VERSION"
    implementation "io.swagger.core.v3:swagger-models:$project.ext.SWAGGER_VERSION"
    implementation 'io.gsonfire:gson-fire:1.9.0'
    generatedCompile "io.swagger.core.v3:swagger-annotations:$project.ext.SWAGGER_VERSION"
    generatedCompile "io.swagger.core.v3:swagger-models:$project.ext.SWAGGER_VERSION"
    generatedCompile 'io.gsonfire:gson-fire:1.9.0'

    // war plugin. Add this to scope of the compile configuration, but do not include in .war file.
    providedCompile group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.1.0'

    __tools__Implementation 'commons-cli:commons-cli:1.9.0'
    __tools__Implementation 'com.opencsv:opencsv:5.9'

    testImplementation 'org.mockito:mockito-core:5.14.2'
    // 1.4.2+ results in a compilation error: reference to assertThat is ambiguous
    testImplementation "com.google.truth:truth:1.4.1"
    // 1.4.197+ results in a small number of test failures in CircleCI
    // 1.4.200+ results in a large number of test failures due to missing DB tables
    testImplementation 'com.h2database:h2:1.4.196'
    testImplementation "org.liquibase:liquibase-core:$project.ext.LIQUIBASE_VERSION"
    testImplementation 'org.bitbucket.radistao.test:before-after-spring-test-runner:0.1.0'

    testImplementation 'org.springframework.boot:spring-boot-test'
    testImplementation 'org.springframework.boot:spring-boot-test-autoconfigure'
    testImplementation ('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'com.vaadin.external.google', module: 'android-json'
    }
}

tasks.compileJava {
    dependsOn 'compileGeneratedJava'
    options.compilerArgs << '-Xlint:unchecked'
}

task integrationTest(type: Test) {
    group = LifecycleBasePlugin.VERIFICATION_GROUP
    description = 'Run integration test suite.'
    testClassesDirs = sourceSets.__integration__.output.classesDirs
    classpath = sourceSets.__integration__.runtimeClasspath
    // These tests should always run when requested since they consume and produce side-effects.
    outputs.upToDateWhen { false }

    useJUnitPlatform()

    // Option to control size of stack trace:
    // jvmArgs '-XX:MaxJavaStackTraceDepth=10'
}

task bigQueryTest(type: Test) {
    group = LifecycleBasePlugin.VERIFICATION_GROUP
    description = 'Runs BigQuery test suite.'
    testClassesDirs = sourceSets.__bigQueryTest__.output.classesDirs
    classpath = sourceSets.__bigQueryTest__.runtimeClasspath

    outputs.upToDateWhen { false }

    useJUnitPlatform()
}

tasks.withType(Test) {
    testLogging {
        // Causes the correct line to be reported on an exception.
        exceptionFormat "full"
    }
    def verboseTestLogging = project.properties['verboseTestLogging'] ?: 'no'
    if (verboseTestLogging == 'yes') {
        testLogging {
            events "passed", "skipped", "failed", "standardOut", "standardError"
        }
    } else {
        testLogging {
            events "passed", "skipped", "failed"
        }
        reports {
            // Write XML file (used by CircleCI, Jenkins, etc) to api/build/test-results/test
            junitXml.required = true
            // Write human-readable test report to api/build/reports/
            html.required = true
        }
    }
    // As of Q1 2021, API unit tests need a larger heap due to memory retention across individual test cases.
    maxHeapSize = "2g"
}

appengine {  // App Engine tasks configuration
    tools {
        // Keep in sync with ci/Dockerfile.circle_build and deploy/Dockerfile
        cloudSdkVersion = '471.0.0'
    }
    run {      // local (dev_appserver) configuration (standard environments only)
        port = 8081                 // default
        host = "0.0.0.0"
        // Allows you to attach a debugger on port 8001 when running locally.
        jvmFlags = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001']
        // Give dev_appserver 2 minutes to start up when running appengineStart; by
        // default it will fail after 1 minute. (This is particularly a problem in CircleCI.)
        startSuccessTimeout = 120

        environment = [GOOGLE_APPLICATION_CREDENTIALS: file("$rootDir/sa-key.json").getAbsolutePath()]
    }

    deploy {   // deploy configuration
        stopPreviousVersion = true  // default - stop the current version
        promote = true              // default - & make this the current version
        // Place holder for required field, we are not using gradle to deploy this APP.
        projectId = "all-of-us-workbench-test"
    }
}

task startCronEmulator(dependsOn: [':appengine-cron-emulator:jar', 'generate_appengine_cron_yaml']) {
    doFirst {
        ext.process = new ProcessBuilder()
                .redirectOutput(ProcessBuilder.Redirect.to(new File("cron-emulator.log")))
                .redirectError(ProcessBuilder.Redirect.to(new File("cron-emulator-err.log")))
                .directory(projectDir)
                .command("java", "-jar",
                        project(":appengine-cron-emulator").jar.archivePath.getPath(),
                        "$projectDir/src/main/webapp/WEB-INF/cron.yaml"
                ).start()

        println "Started Cron Emulator, check cron-emulator-err.log for startup errors (RW-3755)"
    }
}

// AppEngine plugin tasks
project.tasks.appengineRun.dependsOn project.tasks.startCronEmulator
project.tasks.appengineStart.dependsOn project.tasks.startCronEmulator
appengineStart {
    // This task has the side-effect of running a local server, and therefore
    // should not be cacheable.
    outputs.upToDateWhen { false }
}

group = 'org.pmiops.allofus.workbench'
version = '0.1.0'          // Version in generated output

// This restricts the language features that may be used to those at or below the given Java
// version.
sourceCompatibility = 17

// This restricts the runtime environment to be at or above the given Java version.
targetCompatibility = 17

task listProjectAPIs(type: GenerateAPIListingTask)


//
// COMMAND-LINE TOOLS
//
// All tasks below represent scripts meant to be run via Gradle command-line invocations.
//
// This gives us a natural place to put one-off scripts, deployment tasks, or any other
// code that should be run outside the context of a HTTP request or a cron job.


// Define database-related Spring Boot properties required for running
// command-line tools. These are set up elsewhere for the main App Engine
// runtime.
//
// These system variables will have been set by the project.rb script before
// this task is executed.
//
// N.B. these properties should be kept roughly in sync with the App Engine configuration
// XML file under src/main/webapp/WEB-INF/appengine-web.xml
def db_host = System.getenv("DB_HOST")
def db_port = System.getenv("DB_PORT")

// See project.rb command: fetch-firecloud-user-profiles
task fetchFireCloudUserProfile(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.FetchFireCloudUserProfile"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// example run:
// ./project.rb fetch-workspace-details \
// --project all-of-us-workbench-test --workspace-namespace aou-rw-test-d15fd8ee
task fetchWorkspaceDetails(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.FetchWorkspaceDetails"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: generate-impersonated-user-tokens
task generateImpersonatedUserTokens(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.GenerateImpersonatedUserTokens"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: invalidate-rdr-export
task invalidateRdrExport(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.InvalidateRdrExport"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: backfill-entities-to-rdr
task backfillEntitiesToRdr(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.BackfillEntitiesToRdr"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// This task is called from a few different places:
// - devstart.rb > load_config (used by "deploy" and "update_cloud_config" commands)
// - directly via gradlew (used by "run-local-migrations" command)
// - docker-compose.yaml#updateConfig (used by "dev-up" command)
task loadConfig(type: JavaExec) {
    classpath sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.ConfigLoader"
    if (project.hasProperty("config_key") && project.hasProperty("config_file")) {
        args config_key, config_file
    }
}

// Called by devs from the command-line:
// ./project.rb list-runtimes
// ./project.rb delete-runtimes
// ./project.rb describe-runtime
task manageLeonardoRuntimes(type: JavaExec) {
    classpath sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.ManageLeonardoRuntimes"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// Called by devs from the command-line:
// - devstart.rb > set_authority
task setAuthority(type: JavaExec) {
    classpath sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.SetAuthority"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// This task is called from:
// - devstart.rb > update_cdr_config_for_project (called by run-local-migrations)
task updateCdrConfig(type: JavaExec) {
    classpath sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.cdrconfig.UpdateCdrConfig"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: create-wgs-cohort-extraction-bp-workspace
task createWgsCohortExtractionBillingProjectWorkspace(type: JavaExec) {
    classpath sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.CreateWgsCohortExtractionBillingProjectWorkspace"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: create-terra-method-snapshot
task createTerraMethodSnapshot(type: JavaExec) {
    classpath sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.CreateTerraMethodSnapshot"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: load-institutions
task loadInstitutions(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.institutions.LoadInstitutions"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: fix-desynchronized-billing-project-owners
task fixDesynchronizedBillingProjectOwners(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.FixDesynchronizedBillingProjectOwners"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: set-access-module-timestamps
task setAccessModuleTimestamps(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.SetAccessModuleTimestamps"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: export-workspace-operations
task exportWorkspaceOperations(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.ExportWorkspaceOperations"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// See project.rb command: delete-workspaces
task deleteWorkspaces(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.DeleteWorkspaces"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

task backfillGSuiteUserData(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.BackfillGSuiteUserData"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// example run:
// ./project.rb list-disks \
// --project all-of-us-workbench-test \
// --output test-disks.csv
task listDisks(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.ListDisks"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// ./project.rb send-email
task sendEmail(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.SendEmail"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

// ./project.rb run-extraction
task runGenomicExtraction(type: JavaExec) {
    classpath = sourceSets.__tools__.runtimeClasspath
    mainClass = "org.pmiops.workbench.tools.RunGenomicExtractionWorkflow"
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

dependencies {
    modules {
    module("org.aspectj:aspectjrt") { replacedBy("org.aspectj:aspectjweaver") }
    module("org.springframework:spring-jcl") { replacedBy("commons-logging:commons-logging") }

    module("org.apache.tomcat:tomcat-juli") {
      replacedBy("org.apache.tomcat.embed:tomcat-embed-core")
    }
  }
}

explodeWar {
  dependsOn(bootWar)
}



dependencyCheck {
    nvd {
        apiKey = System.getenv('NVD_API_KEY')
    }
}



