pipeline {
    agent none
    parameters {
        string(name: 'REDMINE_VERSION', description: 'The release note will be based on the tickets tagged with the given target version.', trim: true)
        string(name: 'RELEASE_NUMERIC_PREFIX', description: """
The numeric prefix of the release (like 2018.16).
For example for:
- for Gaia.18 it is 2021.07
- for 2022.06 it is 2022.06
- for Helios.05 it is 2021.15
- ...
""", trim: true)
        string(name: 'LTS_BRANCH', description: 'Technical name of the LTS branch (e.g. 2022.10, 2023.10, or master)')
        choice(name: 'RELEASE_TYPE', choices: ['IV', 'BUGFIX'], description: 'Select the type of release')
        string(name: 'SOURCE_RELEASE', description: """
This is the source release (debian packages) that will be used as the source of the new release (same as SOURCE parameter of the job ). For example xivo-2024.10-latest

If RELEASE_TYPE is BUGFIX: this parameter is optional. It will be constructed from RELEASE_NUMERIC_PREFIX.
Otherwise, if RELEASE_TYPE is IV : set it to the last previous Intermediate Version that was released (this IV may be an LTS) : if you're building 2024.11 it should be xivo-2024.10-latest.
""", trim: true)
        booleanParam(name: 'SKIP_RELEASE_NOTES', defaultValue: false, description: 'Skip the release-note job. Requires DOCKER_PROJECTS, DEBIAN_PROJECTS and OTHERS_PROJECTS to be set below.')
        booleanParam(name: 'SKIP_DOCKER', defaultValue: false, description: 'Skip the docker build stage (it already completed in a previous run).')
        booleanParam(name: 'SKIP_DEBIAN', defaultValue: false, description: 'Skip the debian build stage (it already completed in a previous run).')
        booleanParam(name: 'SKIP_DESKTOP', defaultValue: false, description: 'Skip the desktop build and desktop symlink stages (they already completed in a previous run).')
        booleanParam(name: 'SKIP_DAILY_TESTS', defaultValue: false, description: 'Skip the daily-tests stage.')
        string(name: 'DOCKER_PROJECTS', defaultValue: '', description: """
Optional. Overrides the docker project list normally read from the release-note job.
Set it when rerunning a partially failed build, so release-note does not need to run again.
The project lists of every run are printed in the 'resolve-projects' stage, ready to be copied here.
""", trim: true)
        string(name: 'DEBIAN_PROJECTS', defaultValue: '', description: 'Optional. Overrides the debian project list normally read from the release-note job.', trim: true)
        string(name: 'OTHERS_PROJECTS', defaultValue: '', description: 'Optional. Overrides the others project list normally read from the release-note job.', trim: true)
    }
    stages {
        stage('build-release-notes') {
            when {
                expression { !params.SKIP_RELEASE_NOTES }
            }
            agent any
            steps {
                build(
                    job: 'release-note',
                    parameters: [
                        string(name: 'REDMINE_VERSION', value: "${REDMINE_VERSION}"),
                        string(name: 'RELEASE_NUMERIC_PREFIX', value: "${RELEASE_NUMERIC_PREFIX}")],
                    wait: true
                )
            }
        }
        stage('resolve-projects') {
            agent any
            steps {
                script {
                    // Each list falls back to the release-note file on its own, so a
                    // rerun can narrow down a single list and let the others be
                    // resolved as usual.
                    def fromFile = [:]
                    if (params.SKIP_RELEASE_NOTES) {
                        if (!params.DOCKER_PROJECTS && !params.DEBIAN_PROJECTS && !params.OTHERS_PROJECTS) {
                            error "SKIP_RELEASE_NOTES requires at least one project list to be given as a parameter."
                        }
                    } else {
                        fromFile = readProperties file: '/var/lib/jenkins/workspace/release-note/TAGGED_PROJECTS'
                    }

                    DOCKER_PROJECTS = params.DOCKER_PROJECTS ?: "${fromFile['DOCKER_PROJECTS'] ?: ''}"
                    DEBIAN_PROJECTS = params.DEBIAN_PROJECTS ?: "${fromFile['DEBIAN_PROJECTS'] ?: ''}"
                    OTHER_PROJECTS = params.OTHER_PROJECTS ?: "${fromFile['OTHER_PROJECTS'] ?: ''}"

                    echo """Project lists for this release. Copy them as parameters to rerun this build without release-note:
- DOCKER_PROJECTS=${DOCKER_PROJECTS}
- DEBIAN_PROJECTS=${DEBIAN_PROJECTS}
- OTHER_PROJECTS=${OTHER_PROJECTS}"""
                    // Carried in env like the other cross-stage state: a bare assignment
                    // becomes a WorkflowScript field, which Jenkins warns about.
                    env.DESKTOP_IN_RELEASE = OTHER_PROJECTS.split(',').collect { it.trim() }.contains('xivo-desktop-assistant')
                    env.XUCMGT_IN_RELEASE = DOCKER_PROJECTS.split(',').collect { it.trim() }.contains('xucmgt')
                }
            }
        }
        stage('bump-xucmgt-for-desktop') {
            when {
                expression { env.DESKTOP_IN_RELEASE == 'true' && env.XUCMGT_IN_RELEASE != 'true' }
            }
            agent any
            steps {
                script {
                    def desktopRelease = REDMINE_VERSION.substring(0, 10)
                    echo "xivo-desktop-assistant ${desktopRelease} is released but xucmgt is not: bumping xucmgt so it advertises the new desktop version for auto-update."

                    sh """
                        set -e
                        rm -rf xucmgt
                        git clone git@gitlab.com:xivo.solutions/xucmgt.git
                        cd xucmgt
                        xivocc-build.sh set-version ${desktopRelease} ${LTS_BRANCH}
                    """

                    DOCKER_PROJECTS = DOCKER_PROJECTS ? "${DOCKER_PROJECTS},xucmgt" : 'xucmgt'
                }
            }
        }
        stage('build-docker') {
            when {
                expression { !params.SKIP_DOCKER }
            }
            steps {
                script {
                    switch(params.RELEASE_TYPE) {
                        case 'BUGFIX':
                            if (DOCKER_PROJECTS) {
                                build(
                                    job: 'docker-images-rc-build-process',
                                    parameters: [
                                        string(name: 'RELEASE', value: "${REDMINE_VERSION.substring(0,10)}"),
                                        string(name: 'DOCKER_LIST', value: "${DOCKER_PROJECTS}"),
                                        string(name: 'LTS_BRANCH', value: "${LTS_BRANCH}")
                                    ]
                                )
                            } else {
                                echo "No docker to build. Skipping build stage."
                            }
                            break
                        case 'IV':
                            build(
                                job: 'build-all-docker-images',
                                parameters: [
                                    string(name: 'RELEASE', value: "${REDMINE_VERSION.substring(0,10)}"),
                                    string(name: 'BRANCH_OR_TAG', value: "${LTS_BRANCH}"),
                                    string(name: 'BUILD_MODE', value: 'rc')
                                ]
                            )
                            break
                        default:
                            error("Invalid RELEASE_TYPE: ${params.RELEASE_TYPE}")
                    }
                }
            }
        }
        stage('build-debian') {
            when {
                expression { !params.SKIP_DEBIAN }
            }
            steps {
                script {
                    def DEBIAN_PROJECTS_WITHOUT_ASTERISK = DEBIAN_PROJECTS.split(',').findAll { it.trim() != 'asterisk' }.join(',')

                    if (!DEBIAN_PROJECTS_WITHOUT_ASTERISK) {
                        DEBIAN_PROJECTS_WITHOUT_ASTERISK = 'xivo'
                        echo "No debian project to build: adding 'xivo' anyway to bump the version and have the debian part released."
                    }

                    switch(params.RELEASE_TYPE) {
                        case 'BUGFIX':
                            build(
                                job: 'debian-packages-rc-build-process',
                                parameters: [
                                    string(name: 'RELEASE', value: "${REDMINE_VERSION.substring(0,10)}"),
                                    string(name: 'PACKAGER_LIST', value: "${DEBIAN_PROJECTS_WITHOUT_ASTERISK}"),
                                    string(name: 'SOURCE', value: "xivo-${RELEASE_NUMERIC_PREFIX}-latest")
                                ]
                            )
                            break
                        case 'IV':
                            if (SOURCE_RELEASE == "") {
                                error("SOURCE_RELEASE cannot be empty for RELEASE_TYPE IV")
                            }
                            build(
                                job: 'debian-packages-rc-build-process',
                                parameters: [
                                    string(name: 'RELEASE', value: "${REDMINE_VERSION.substring(0,10)}"),
                                    string(name: 'PACKAGER_LIST', value: "${DEBIAN_PROJECTS_WITHOUT_ASTERISK}"),
                                    string(name: 'SOURCE', value: "${SOURCE_RELEASE}"),
                                    booleanParam(name: 'DO_PROD_RELEASE', value: false)
                                ]
                            )
                            break
                        default:
                            error("Invalid RELEASE_TYPE: ${params.RELEASE_TYPE}")
                    }
                }
            }
        }
        stage('check-and-bump-desktop') {
            when {
                expression { env.DESKTOP_IN_RELEASE == 'true' }
            }
            agent any
            steps {
                script {
                    env.DESKTOP_RELEASE = REDMINE_VERSION.substring(0, 10)
                    env.DESKTOP_SEMVER = env.DESKTOP_RELEASE.split('\\.').collect { it.toInteger() }.join('.')

                    def tagAlreadyExists = sh(
                        script: 'git ls-remote --exit-code --tags git@gitlab.com:xivo.solutions/xivo-desktop-assistant.git "refs/tags/${DESKTOP_RELEASE}-rc"',
                        returnStatus: true
                    ) == 0

                    if (tagAlreadyExists) {
                        env.DESKTOP_ALREADY_RELEASED = 'true'
                        echo "xivo-desktop-assistant ${env.DESKTOP_RELEASE}-rc is already tagged and built. Skipping desktop build and tagging."
                        return
                    }

                    env.DESKTOP_ALREADY_RELEASED = 'false'
                    sh '''
                        set -e
                        rm -rf xivo-desktop-assistant
                        git clone git@gitlab.com:xivo.solutions/xivo-desktop-assistant.git
                        cd xivo-desktop-assistant
                        git checkout "${LTS_BRANCH}"

                        npm version "${DESKTOP_SEMVER}" --no-git-tag-version --allow-same-version
                        git add package.json package-lock.json
                        git commit -m "Bump to ${DESKTOP_SEMVER}" || echo "Version already at ${DESKTOP_SEMVER}, nothing to commit"
                        git push origin "${LTS_BRANCH}"
                    '''
                }
            }
        }
        stage('build-desktop') {
            when {
                expression { env.DESKTOP_IN_RELEASE == 'true' && env.DESKTOP_ALREADY_RELEASED != 'true' }
            }
            steps {
                build(
                    job: '/DesktopApp/build-dapp-v2',
                    parameters: [
                        string(name: 'BRANCH_OR_TAG', value: "${LTS_BRANCH}"),
                        booleanParam(name: 'SKIP_MSI_BUILD', value: false),
                        booleanParam(name: 'SKIP_APPIMAGE_BUILD', value: false),
                        booleanParam(name: 'SKIP_ELECTRON_INTEGRATION_TESTS', value: false),
                        string(name: 'ELECTRON_BUILDER_IMAGE_TAG', value: ''),
                        booleanParam(name: 'SIGNED_DESKTOP', value: true),
                        booleanParam(name: 'PUSH_ON_MIRROR', value: true)
                    ]
                )
            }
        }
        stage('tag-desktop') {
            when {
                expression { env.DESKTOP_IN_RELEASE == 'true' && env.DESKTOP_ALREADY_RELEASED != 'true' }
            }
            agent any
            steps {
                sh '''
                    set -e
                    rm -rf xivo-desktop-assistant
                    git clone git@gitlab.com:xivo.solutions/xivo-desktop-assistant.git
                    cd xivo-desktop-assistant
                    git checkout "${LTS_BRANCH}"

                    built_semver=$(node -p "require('./package.json').version")
                    if [ "${built_semver}" != "${DESKTOP_SEMVER}" ]; then
                        echo "${LTS_BRANCH} is at ${built_semver} but ${DESKTOP_SEMVER} was built: refusing to tag." >&2
                        exit 1
                    fi

                    git tag -a "${DESKTOP_RELEASE}-rc" -m "${DESKTOP_RELEASE} Release candidate"
                    git push origin "${DESKTOP_RELEASE}-rc"
                '''
            }
        }
        stage('symlink-desktop') {
            when {
                expression {
                    !params.SKIP_DESKTOP &&
                    env.DESKTOP_IN_RELEASE != 'true' &&
                    DOCKER_PROJECTS.split(',').collect { it.trim() }.contains('xucmgt')
                }
            }
            agent any
            steps {
                script {
                    env.VERSION_TO_PUBLISH = (REDMINE_VERSION =~ /[0-9]{4}\.[0-9]{2}\.[0-9]{2}/)[0]
                }
                sh '''
                    ssh root@192.168.225.14 bash -s -- "${VERSION_TO_PUBLISH}" << 'ENDSSH'
#!/bin/bash
set -e

version_to_publish=$1
dapp_dir="/var/www/mirror.xivo.solutions/xivo-desktop-assistant"
version_full=$(echo ${version_to_publish} | grep -oE '[0-9]{4}\\.[0-9]{2}\\.[0-9]{2}')
version_major=$(echo ${version_full} | grep -oE '[0-9]{4}\\.[0-9]{2}')

target_link="${dapp_dir}/${version_major}/${version_full}"

# An existing link means this stage already ran for this version: report it and
# leave it untouched so the release is not published twice.
if [ -L "${target_link}" ]; then
    echo "${target_link} already links to $(readlink ${target_link})."
    echo "This version has already been published, nothing to do."
    exit 0
fi

if [ -e "${target_link}" ]; then
    echo "${target_link} already exists and is not a symlink." >&2
    echo "Refusing to touch it, please check it by hand." >&2
    exit 1
fi

previous_version=$(find "${dapp_dir}" -mindepth 2 -maxdepth 2 -type d | grep -oE '[0-9]{4}\\.[0-9]{2}\\.[0-9]{2}' | sort -u | awk -v cur="${version_full}" '$0 < cur' | tail -1)

if [ -z "${previous_version}" ]; then
    echo "No previous desktop-assistant version older than ${version_full} found under ${dapp_dir}" >&2
    exit 1
fi

mkdir -p ${dapp_dir}/${version_major}

previous_version_full=$(echo ${previous_version} | grep -oE '[0-9]{4}\\.[0-9]{2}\\.[0-9]{2}')
previous_version_major=$(echo ${previous_version_full} | grep -oE '[0-9]{4}\\.[0-9]{2}')

cd ${dapp_dir}/${version_major}
ln -s ../${previous_version_major}/${previous_version_full} ${version_full}

echo "So here's what it looks like in ${version_major} dir:"
ls -l ${dapp_dir}/${version_major}
ENDSSH
                '''
            }
        }
        stage('daily-tests') {
            when {
                expression { !params.SKIP_DAILY_TESTS }
            }
            steps {
                script {
                    def versionToCompare = "2023.05.12"
                    def currentVersion = REDMINE_VERSION.substring(0,10)

                    if (currentVersion >= versionToCompare) {
                        build(
                            job: 'daily-tests',
                            parameters: [
                                string(name: 'VERSION', value: currentVersion)
                            ]
                        )
                    } else {
                        echo "Skipping daily-tests as version ${currentVersion} is older than ${versionToCompare}"
                    }
                }
            }
        }
    }
}
