/*
** Copyright (c) 2026 Valve Corporation
** Copyright (c) 2026 LunarG, Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the "Software"),
** to deal in the Software without restriction, including without limitation
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
** and/or sell copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
*/

def devTestedCommit = null
def scriptLabel = 'Linux'

def gitRemoteCredentialsId(scmConfig) {
    def remoteConfig = scmConfig.userRemoteConfigs?.first()
    if (!remoteConfig?.credentialsId) {
        error('Unable to resolve Git credentials ID from Jenkins SCM configuration')
    }
    return remoteConfig.credentialsId
}

pipeline {
    // Do not reserve one Jenkins agent for the whole pipeline.  Each stage or
    // test branch asks for the agent it needs with node { ... }.
    agent none

    options {
        // Only one build of a branch should run at a time.  For dev, a newer
        // build aborts an older one instead of letting both publish candidates.
        disableConcurrentBuilds(abortPrevious: true)
    }

    stages {
        stage('Per Commit Tests') {
            steps {
                script {
                    // different log rotator settings for dev vs PRs
                    def discarder = env.BRANCH_NAME == 'dev'
                        ? buildDiscarder(logRotator(
                            daysToKeepStr: '90',
                            artifactDaysToKeepStr: '14'
                        ))
                        : buildDiscarder(logRotator(
                            daysToKeepStr: '14',
                            artifactNumToKeepStr: '3'
                        ))
                    properties([discarder])

                    def tests

                    // Checkout and load on any available node
                    node {
                        // checkout scm checks out the branch/commit Jenkins is
                        // building and returns metadata from the Git plugin.
                        def scmVars = checkout scm
                        // Save the exact commit tested by this dev build.  Do
                        // not use the dev branch name later because it can move.
                        devTestedCommit = scmVars.GIT_COMMIT
                        // load evaluates runJob.groovy and returns its map of
                        // labels and helper functions for creating test stages.
                        def runJob = load 'ci/runJob.groovy'

                        tests = [
                            'Android Rel64': runJob.gfxrTestAndroid('Android R64', runJob.ReleaseMode, runJob.AndroidLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            // 'Android Dbg32': runJob.gfxrTestAndroid('Android D32', runJob.DebugMode, runJob.AndroidLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Linux Mesa Rel64': runJob.gfxrTestLinux('Linux Mesa Rel64', runJob.ReleaseMode, runJob.LinuxMesaLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Linux Mesa Dbg32': runJob.gfxrTestLinux('Linux Mesa Dbg32', runJob.DebugMode, runJob.LinuxMesaLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Linux Nnvidia Rel64': runJob.gfxrTestLinux('Linux Nvidia Rel64', runJob.ReleaseMode, runJob.LinuxNvidiaLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Linux Nnvidia Dbg32': runJob.gfxrTestLinux('Linux Nvidia Dbg32', runJob.DebugMode, runJob.LinuxNvidiaLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Linux Mesa 9070 Rel64': runJob.gfxrTestLinux('Linux Mesa 9070 Rel64', runJob.ReleaseMode, runJob.LinuxMesa9070Label, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Linux Mesa 9070 Dbg32': runJob.gfxrTestLinux('Linux Mesa 9070 Dbg32', runJob.DebugMode, runJob.LinuxMesa9070Label, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Linux Nvidia 5080 Rel64': runJob.gfxrTestLinux('Linux Nvidia 5080 Rel64', runJob.ReleaseMode, runJob.LinuxNvidia5080Label, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Linux Nvidia 5080 Dbg32': runJob.gfxrTestLinux('Linux Nvidia 5080 Dbg32', runJob.DebugMode, runJob.LinuxNvidia5080Label, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Mac': runJob.gfxrTestLinux('Mac', runJob.ReleaseMode, runJob.MacLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows AMD Rel64': runJob.gfxrTestWindows('Win AMD Rel64', runJob.ReleaseMode, runJob.WinAMDLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows AMD Dbg32': runJob.gfxrTestWindows('Win AMD Dbg32', runJob.DebugMode, runJob.WinAMDLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows Nvidia Rel64': runJob.gfxrTestWindows('Win Nvidia Rel64', runJob.ReleaseMode, runJob.WinNvidiaLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows Nvidia Dbg32': runJob.gfxrTestWindows('Win Nvidia Dbg32', runJob.DebugMode, runJob.WinNvidiaLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows11 AMD Rel64': runJob.gfxrTestWindows('Win11 AMD Rel64', runJob.ReleaseMode, runJob.Win11AMDLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 AMD Dbg32': runJob.gfxrTestWindows('Win11 AMD Dbg32', runJob.DebugMode, runJob.Win11AMDLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows11 ARM Rel64': runJob.gfxrTestWindows('Win11 ARM Rel64', runJob.ReleaseMode, runJob.Win11ARMLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 ARM Dbg64': runJob.gfxrTestWindows('Win11 ARM Dbg64', runJob.DebugMode, runJob.Win11ARMLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 AMD 9070 Rel64': runJob.gfxrTestWindows('Win11 AMD 9070 Rel64', runJob.ReleaseMode, runJob.Win11AMD9070Label, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 AMD 9070 Dbg32': runJob.gfxrTestWindows('Win11 AMD 9070 Dbg32', runJob.DebugMode, runJob.Win11AMD9070Label, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows11 Nvidia 5080 Rel64': runJob.gfxrTestWindows('Win11 Nvidia 5080 Rel64', runJob.ReleaseMode, runJob.Win11Nvidia50XXLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 Nvidia 5080 Dbg32': runJob.gfxrTestWindows('Win11 Nvidia 5080 Dbg32', runJob.DebugMode, runJob.Win11Nvidia50XXLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                        ]
                    }
                    // Run the test closures in parallel.  This is outside the
                    // setup node above, so each closure allocates its own test
                    // machine instead of sharing one workspace.
                    parallel tests
                }
            }
        }

        stage('Publish Extended Candidate') {
            when {
                allOf {
                    // Only the dev branch publishes a candidate for the scheduled
                    // extended job.  PR and other branch builds only run commit tests.
                    branch 'dev'
                    // Some test helpers use catchError, which marks the build
                    // failed but lets the pipeline continue.  Do not publish a
                    // candidate unless every parallel test branch succeeded.
                    expression { return currentBuild.currentResult == 'SUCCESS' }
                }
            }

            steps {
                script {
                    if (!devTestedCommit?.trim()) {
                        error('Unable to resolve tested commit SHA')
                    }

                    // The marker update script uses sh, so run it on a Linux
                    // agent.  It pushes refs/heads/ci/gfxr-dev-tested to the
                    // exact commit this dev build validated.
                    node(scriptLabel) {
                        // This node has a fresh workspace, so checkout before
                        // running the script from the repository.
                        checkout scm
                        withCredentials([gitUsernamePassword(
                            credentialsId: gitRemoteCredentialsId(scm),
                            gitToolName: 'Default'
                        )]) {
                            sh "./ci/updateDevTestedRef.sh ${devTestedCommit.trim()}"
                        }
                    }
                }
            }
        }
    }

    post {
        failure {
            script {
                if (env.BRANCH_NAME == 'dev') {
                    node {
                        googlechatnotification(
                            url: 'id:Google-Chat-GFXR',
                            message: "Build failed: <${env.BUILD_URL}|${env.BRANCH_NAME} #${env.BUILD_NUMBER}>",
                            notifyFailure: false,
                        )
                    }
                }
            }
        }
    }
}
