tasks/python.tasks.ps1

$SkipInstallPythonPoetry = $false
$SkipInitialisePythonPoetry = $false
$SkipRunFlake8 = $false
$SkipRunPyTest = $false
$SkipBuildPythonPackages = $false
$SkipPublishPythonPackages = $false

$PythonPoetryProject = ""
$PythonPublishUser = "user"
$PythonRepositoryName = "ci-python-feed"
$PythonPackageRepoUrl = ""      # e.g. https://pkgs.dev.azure.com/myOrg/Project/_packaging/myfeed/pypi/upload
$PoetryPath = Get-Command poetry -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path

task EnsurePython -If { $PythonPoetryProject -ne "" } {

    if (!(Get-Command python -ErrorAction SilentlyContinue)) {
        throw "A Python installation could not be found. Please install Python and ensure it is available on the PATH environment variable."
    }
}
task InstallPythonPoetry -If { !$SkipInstallPythonPoetry } EnsurePython,{

    if (!$PoetryPath) {       
        # The install script will honour this environment variable, we override the default here to ensure
        # a consistent location across platforms
        $poetryBaseDir = $IsWindows ? $env:USERPROFILE : $env:HOME
        $env:POETRY_HOME ??= "$poetryBaseDir{0}.poetry" -f [System.IO.Path]::DirectorySeparatorChar

        Write-Build White "Installing Poetry"
        Invoke-WebRequest -Uri https://install.python-poetry.org/ -OutFile get-poetry.py
        exec { & python get-poetry.py --yes }
        Remove-Item get-poetry.py
 
        $poetryBinPath = Join-Path $env:POETRY_HOME "bin"
        $script:PoetryPath = Join-Path $poetryBinPath "poetry"
        # Add poetry to the current PATH environment variable, if not already there
        if ($poetryBinPath -notin ($env:PATH -split [System.IO.Path]::PathSeparator)) {
            $env:PATH = "$poetryBinPath{0}$env:PATH" -f [System.IO.Path]::PathSeparator
        }
    }
    else {
        Write-Build Green "Poetry already installed"
    }
}

task UpdatePoetryLockfile -If { !$IsRunningOnBuildServer } InstallPythonPoetry,{
    Write-Build White "Ensuring poetry.locl is up-to-date - no packages will be updated"
    exec { & $script:PoetryPath lock --no-update }
}

task InitialisePythonPoetry -If { $PythonPoetryProject -ne "" -and !$SkipInitialisePythonPoetry } InstallPythonPoetry,UpdatePoetryLockfile,{
    if (!(Test-Path (Join-Path $PythonPoetryProject "pyproject.toml"))) {
        throw "pyproject.toml not found in $PythonPoetryProject"
    }

    # Default to using virtual environments in the project directory, unless already set
    $env:POETRY_VIRTUALENVS_IN_PROJECT ??= "true"

    # Define the global poetry arguments we will use for all poetry commands
    $script:poetryGlobalArgs = @(
        "--no-interaction"
        "--directory=$PythonPoetryProject"
        "-v"
    )
    Write-Build White "poetryGlobalArgs: $poetryGlobalArgs"

    exec { & $script:PoetryPath install @poetryGlobalArgs --with dev,test }
}

task RunFlake8 -If { $PythonPoetryProject -ne "" -and !$SkipRunFlake8 } InitialisePythonPoetry,{
    Write-Build White "Running flake8"
    Push-Location $PythonPoetryProject
    exec { & $script:PoetryPath run --no-interaction -v flake8 src -vv }
    Pop-Location
}

task RunPyTests -If { $PythonPoetryProject -ne "" -and !$SkipRunPyTest } InitialisePythonPoetry,{
    Push-Location $PythonPoetryProject
    exec {
        & $script:PoetryPath run --no-interaction -v `
            pytest `
            --cov=src `
            --cov-report=xml:$CoverageDir/coverage.xml `
            --cov-report=term-missing `
            --junitxml=$here/pytest-test-results.xml
    }
    Pop-Location
}

task BuildPythonPackages -If { $PythonPoetryProject -ne "" -and !$SkipBuildPythonPackages } GitVersion,InitialisePythonPoetry,{
    if (Test-Path (Join-Path $PythonPoetryProject "dist")) {
        Remove-Item (Join-Path $PythonPoetryProject "dist") -Recurse -Force
    }
    exec { & $script:PoetryPath version @poetryGlobalArgs $GitVersion.MajorMinorPatch }
    # For the moment we accept that wheel files will be created in the 'dist' directory,
    # rather than ending up in $PackagesDir
    exec { & $script:PoetryPath build @poetryGlobalArgs --format=wheel }
}

task PublishPythonPackages -If { $PythonPoetryProject -ne "" -and !$SkipPublishPythonPackages } InitialisePythonPoetry,{
    if (!$PythonPackageRepoUrl) {
        Write-Warning "PythonPackageRepoUrl build variable not set, skipping publish"
    }
    elseif (!$env:PYTHON_PACKAGE_REPOSITORY_KEY) {
        Write-Warning "PYTHON_PACKAGE_REPOSITORY_KEY environment variable not set, skipping publish"
    }
    else {
        exec {
            Write-Build White "Registering Python repository $PythonRepositoryName -> $PythonPackageRepoUrl"
            & $script:PoetryPath config @poetryGlobalArgs repositories.$PythonRepositoryName $PythonPackageRepoUrl
        }

        exec {
            Write-Build White "Publishing Python packages to $PythonRepositoryName"
            & $script:PoetryPath publish @poetryGlobalArgs -u $PythonPublishUser -p $env:PYTHON_PACKAGE_REPOSITORY_KEY -r $PythonRepositoryName
        }
    }
}