pipeline {
  agent {
    dockerfile {
      filename    'Dockerfile'       // name of the Dockerfile
      dir         '.ci/agent'        // relative path in workspace
      additionalBuildArgs '--pull'   // e.g. force fresh base image
      label       'built-in'         // node label that can run Docker
      reuseNode   true               // if true, image build and container pipeline run happen on same host 
    }
  }
  stages {
    stage('Clean workspace to start on clean canvas') {
      steps {
        deleteDir()
      }
    }

    stage('Checkout') {
      steps {
        checkout([
          $class: 'GitSCM',

          // inherit the same remotes (URL + credentials) that "checkout scm" would use
          userRemoteConfigs: scm.userRemoteConfigs,

          // your branch selector
          branches: [[ name: "*/${env.BRANCH_NAME}" ]],

          doGenerateSubmoduleConfigurations: false,
          extensions: [
            [$class: 'CloneOption', shallow: false, noTags: false, depth: 0],
            [$class: 'PruneStaleBranch']
          ]
        ])
      }
    }


    stage('Determine Version') {
      steps {
        script {
          withCredentials([
            string(credentialsId: 'jenkins-git-username', variable: 'GIT_NAME'),
            string(credentialsId: 'jenkins-git-email', variable: 'GIT_EMAIL')
          ]) {
            // initialize git tag version if any already used
            // - will push to remote 0.0.0 only as initialization
            def latestTag = sh(returnStdout: true, script: "git describe --tags --abbrev=0 || echo ''").trim()
            echo "Latest tag is: ${latestTag}"

            def hasTags = latestTag != ''
            if (!hasTags) {
              // inception
              // - start with 0.0.0 and will cause increment to 0.0.1 -> which is first tag truly written
              // - push of first tag 0.0.1 happens, in line with any other push, after all other build operations are done
              latestTag = "0.0.0"
            }

            // manual override checks
            // - an options for manual override is allowed in filename overrideFile at repo root
            // - if exists, it has priority, provided it passes validations (version must be greater than current version etc.)
            def overrideFile = 'VERSION_OVERRIDE'
            def computeAutoVersion = {
              def parts = latestTag.tokenize('.').collect { it.toInteger() }
              def (maj, min, pat) = parts
              return "${maj}.${min}.${pat + 1}"
            }

            if (fileExists(overrideFile)) {
              def manual = readFile(overrideFile).trim()

              def sorted = sh(
                returnStdout: true,
                script: "printf '%s\n%s\n' '${latestTag}' '${manual}' | sort -V"
              ).readLines()

              if (manual != latestTag && sorted[-1] == manual) {
                env.VERSION = manual
                echo "Using validated override version: ${env.VERSION}"
              } else {
                echo "Manual version '${manual}' is not a valid override (must be strictly greater than '${latestTag}'); falling back."
                env.VERSION = computeAutoVersion()
                echo "Auto-incremented version: ${env.VERSION}"
              }
            } else {
              env.VERSION = computeAutoVersion()
              echo "Auto-incremented version: ${env.VERSION}"
            }

          }
        }
      }
    }

    stage('Tag Release') {
      steps {
        withCredentials([
          string(credentialsId: 'jenkins-git-username', variable: 'GIT_NAME'),
          string(credentialsId: 'jenkins-git-email', variable: 'GIT_EMAIL'),
          string(credentialsId: 'gitea-fqdn', variable: 'GITEA_FQDN'),
          usernamePassword(
            credentialsId: 'gitea-pat-for-jenkins-cicd-basicauthform',
            usernameVariable: 'GITEA_USER',
            passwordVariable: 'GITEA_TOKEN'
          )
        ]) {
          sh '''
            git config user.name "$GIT_NAME"
            git config user.email "$GIT_EMAIL"
          '''
          
          sh '''
            # write a throw-away ~/.netrc that Git/libcurl will read
            cat > $HOME/.netrc <<EOF
machine ${GITEA_FQDN}
  login ${GITEA_USER}
  password ${GITEA_TOKEN}
EOF
            chmod 600 $HOME/.netrc
          '''

          sh """
            git tag -a ${env.VERSION} -m "Release ${env.VERSION}"
            git push origin ${env.VERSION}
          """

          echo "Tagged and pushed version with ${env.VERSION}"
        }
      }
    }

    stage('Build') {
      steps {
        // produces build assets dist/*.whl and dist/*.tar.gz
        sh 'python3 -m build'
      }
    }

    stage('Publish to Devpi') {
      steps {
        withCredentials([
          string(credentialsId: 'devpi-url', variable: 'DEVPI_URL'),
          usernamePassword(
            credentialsId: 'devpi-credentials',
            usernameVariable: 'DEVPI_USER',
            passwordVariable: 'DEVPI_PASSWORD'
          )
        ]) {
          sh '''
            twine upload \
              --repository-url ${DEVPI_URL} \
              -u ${DEVPI_USER} -p ${DEVPI_PASSWORD} \
              dist/*
          '''
        }
      }
    }
  }
}
