List<String> AWS_REGIONS = ['us-east-1']
String BACKUP_ACCOUNT_ID = '079637511089'
String BACKUP_DEPLOYMENT_ROLE = 'backup-jenkins-pipeline-deploy-role'
String ECR_ACCOUNT_ID = '086679231553'

PROJECT_CONFIG = [
    "orcd_github_repo_backup": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        services: [
            [environment: 'backup', serviceName: 'orcd-github-repo-backup']
        ],
        serviceType: 'FARGATE',
        deployType: 'UPDATE_CLOUDWATCH_EVENT',
        imageName: 'orcd-github-repo-backup'
    ],
    "orcd_secrets_manager_secrets_backup/fargate": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        services: [
            [environment: 'backup', serviceName: 'orcd-secrets-manager-secrets']
        ],
        serviceType: 'FARGATE',
        deployType: 'CREATE_TASK_DEFINITION',
        imageName: 'orcd-secrets-manager-secrets'
    ],
    "orcd_secrets_manager_secrets_backup/lambda": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        services: [
            [environment: 'backup', serviceName: 'lambda-secrets-manager-backup-trigger']
        ],
        serviceType: 'LAMBDA',
        vulnerabilitiesToIgnore: [
            'CVE-2024-6345',
        ],
        imageName: 'lambda-secrets-manager-backup-trigger',
        vulnerabilitiesToIgnore: [
            'CVE-2025-22871',
            'CVE-2025-68121',
            'CVE-2025-47273',
            'CVE-2025-47907',
            'CVE-2025-58187',
            'CVE-2025-58188',
            'CVE-2025-61723',
            'CVE-2025-61725',
            'CVE-2025-61726',
            'CVE-2025-61729',
            'CVE-2025-66418',
            'CVE-2025-66471',
            'CVE-2026-21441',
            "CVE-2024-6345"
        ]
    ],
    "splitio_ff_backup": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        dockerBuildTarget: 'deploy',
        services: [
            [environment: 'backup', serviceName: 'splitio-ff-backup']
        ],
        serviceType: 'FARGATE',
        deployType: 'UPDATE_CLOUDWATCH_EVENT',
        imageName: 'splitio-ff-backup'
    ],
    "route53_backup/fargate": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        services: [
            [environment: 'backup', serviceName: 'route53-backup']
        ],
        serviceType: 'FARGATE',
        deployType: 'CREATE_TASK_DEFINITION',
        imageName: 'route53-backup'
    ],
    "route53_backup/lambda": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        services: [
            [environment: 'backup', serviceName: 'lambda-route53-backup-trigger']
        ],
        serviceType: 'LAMBDA',
        vulnerabilitiesToIgnore: [
            'CVE-2024-46800',
            'CVE-2024-44974',
            'CVE-2024-46738',
            'CVE-2024-46782',
            'GHSA-87m9-rv8p-rgmg',
            'CVE-2024-46743',
            'CVE-2024-36129',
            'CVE-2024-46744'
        ],
        imageName: 'lambda-route53-backup-trigger',
        vulnerabilitiesToIgnore: [
            'CVE-2025-22871',
            'CVE-2025-68121',
            'CVE-2025-47907',
            'CVE-2025-58187',
            'CVE-2025-58188',
            'CVE-2025-61723',
            'CVE-2025-61725',
            'CVE-2025-61726',
            'CVE-2025-61729'
        ]
    ],
    "s3_restore/lambda": [
        awsDeploymentTargetAccountId: BACKUP_ACCOUNT_ID,
        awsDeploymentRoleName: BACKUP_DEPLOYMENT_ROLE,
        regions: ['us-east-2'],
        services: [],
        serviceType: 'LAMBDA',
    ]
]

pipeline {
    agent none

    options {
        timestamps()
        disableConcurrentBuilds()
    }

    parameters {
        string(name: 'PROJECTS', defaultValue: '', description: "Comma-separated list of projects to build. If not specified, all modified projects will be built.<br><p>Options:</p><ul><li>${PROJECT_CONFIG.keySet().join('</li><li>')}</li></ul>")
        string(name: 'SHARED_LIBRARIES_VERSION', defaultValue: 'master', description: 'The version of the Jenkins shared libraries to use. Can be a branch, tag or Git revision.')
    }

    triggers {
        issueCommentTrigger('.*retest this please.*')
    }

    stages {
        stage('Load Shared Libraries') {
            steps {
                library "jenkins-global-libraries@${params.SHARED_LIBRARIES_VERSION}"
            }
        }
        stage('Compliance Checks') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    dir(project) {
                        complianceChecks()
                    }
                }
            }
        }
        stage('Validate Software Catalog Definitions') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    datadogSoftwareCatalogValidate(servicePath: project)
                }
            }
        }
        stage('Unit Tests and Style Checks') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    dir(project) {
                        // Ensure unique Docker compose project names to avoid conflicts
                        withEnv(["COMPOSE_PROJECT_NAME=${env.BUILD_TAG.toLowerCase()}-${project.replaceAll('/', '-')}"]) {
                            withEcr {
                                script {
                                    try {
                                        sh 'make ci_unit_lint'
                                    }
                                    finally {
                                        sh 'make ci_unit_lint_clean'
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        stage('PR Review') {
            agent any
            when {
                not { branch 'master' }
            }
            steps {
                aiPullRequestReview(projectType: 'python')
            }
        }
        stage('Static Application Security Tests') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    sastTests(projectDir: project)
                }
            }
        }
        stage('Create a Release') {
            when {
                anyOf {
                    branch 'master'
                    expression { env.GITHUB_COMMENT =~ 'build docker' }
                    expression { pullRequest.labels.contains('build docker') }
                }
            }
            steps {
                withModifiedProjects { project, config ->
                    dockerToEcr awsRegions: config['regions'] ?: AWS_REGIONS,
                        ecrAccountId: ECR_ACCOUNT_ID,
                        imageName: config['imageName'],
                        imageTag: env.GIT_COMMIT,
                        dockerBuildContext: project,
                        dockerBuildFile: "${project}/Dockerfile",
                        dockerBuildTarget: config['dockerBuildTarget']
                }
            }
        }
        stage('Scan Docker Image') {
            when {
                anyOf {
                    branch 'master'
                    expression { env.GITHUB_COMMENT =~ 'build docker' }
                    expression { pullRequest.labels.contains('build docker') }
                }
            }
            steps {
                withModifiedProjects { project, config ->
                    dockerScan awsRegion: config['regions'] ? config['regions'][0] : AWS_REGIONS[0],
                        ecrAccountId: ECR_ACCOUNT_ID,
                        imageName: config['imageName'],
                        imageTag: env.GIT_COMMIT,
                        vulnerabilitiesToIgnore: config.get('vulnerabilitiesToIgnore', [])

                }
            }
        }
        stage('Deploy') {
            when {
                branch 'master'
            }
            steps {
                withModifiedProjects { project, config ->
                    script {
                        parallel(config.get('services', []).collectEntries { service ->
                            [
                                "${service['environment']}-${service['serviceName']}": {
                                    if (config['serviceType'] == 'LAMBDA') {
                                        lambdaDeploy environment: service['environment'],
                                            awsRegions: config['regions'] ?: AWS_REGIONS,
                                            imageTag: env.GIT_COMMIT,
                                            imageName: config['imageName'],
                                            ecrRegistryAccountId: ECR_ACCOUNT_ID,
                                            ecrRegistryRegion: config['regions'] ? config['regions'][0] : AWS_REGIONS[0],
                                            awsDeploymentTargetAccountId: config['awsDeploymentTargetAccountId'],
                                            awsDeploymentRoleName: config['awsDeploymentRoleName']
                                    } else {
                                        fargateDeploy environment: service['environment'],
                                            awsRegions: config['regions'] ?: AWS_REGIONS,
                                            gitCommit: env.GIT_COMMIT,
                                            serviceName: service['serviceName'],
                                            ecrRegistryAccountId: ECR_ACCOUNT_ID,
                                            ecrRegistryRegion: config['regions'] ? config['regions'][0] : AWS_REGIONS[0],
                                            awsDeploymentTargetAccountId: config['awsDeploymentTargetAccountId'],
                                            awsDeploymentRoleName: config['awsDeploymentRoleName'],
                                            deployType: config['deployType'],
                                            clusterName: service['clusterName'],
                                            imageNameOverride: config['imageName']
                                    }
                                }
                            ]
                        })
                    }
                }
            }
        }
        stage('Publish Software Catalog Definition') {
            when {
                branch 'master'
            }
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    datadogSoftwareCatalogPublish(servicePath: project)
                }
            }
        }
    }
}

def withModifiedProjects(Map args = [:], Closure steps) {
    getMonorepoUtils().withModifiedProjects(args, steps)
}

def getMonorepoUtils() {
    return library("jenkins-global-libraries@${params.SHARED_LIBRARIES_VERSION}").com.sonymusic.MonorepoUtils.getInstance(
        steps: this,
        projectConfig: PROJECT_CONFIG,
        projectsToBuild: params.PROJECTS ? params.PROJECTS.split(',') : null
    )
}
