diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml deleted file mode 100644 index a375a0d..0000000 --- a/.github/workflows/label.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: "Pull Request Labeler" -on: - pull_request_target: - paths: - - '**/__init__.py' -jobs: - triage: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - # Add labels based on file changes using label.yml - - uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - configuration-path: .github/labeler.yml diff --git a/README.md b/README.md index fd235d8..f233fff 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,15 @@ ## Overview -Python support for Azure Functions is based on Python 3.10, 3.11, 3.12, and 3.13 serverless hosting on Linux, and the Functions 2.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)), 3.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)) and 4.0 runtime. +Python support for Azure Functions is based on Python 3.11, 3.12, 3.13, 3.14, and 3.15 serverless hosting on Linux, and the Functions 2.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)), 3.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)) and 4.0 runtime. Here is the current status of Python in Azure Functions: _What are the supported Python versions?_ -| Azure Functions Runtime | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 | -|----------------------------------|------------|------------|-------------|-------------| -| Azure Functions 4.0 | ✔ | ✔ | ✔ | ✔ | | ✓ | ✓ | ✓ | +| Azure Functions Runtime | Python 3.11 | Python 3.12 | Python 3.13 | Python 3.14 | Python 3.15 | +|-------------------------|-------------|-------------|-------------|-------------|-------------| +| Azure Functions 4.0 | ✔ | ✔ | ✔ | ✔ | ✔ | _What's available?_ - Build, test, debug and publish using Azure Functions Core Tools (CLI) or Visual Studio Code diff --git a/eng/ci/library-release.yml b/eng/ci/library-release.yml index 202a7bd..7769a65 100644 --- a/eng/ci/library-release.yml +++ b/eng/ci/library-release.yml @@ -85,6 +85,7 @@ extends: libraryVersion: ${{ parameters.V1LibraryVersion }} projectDisplayName: 'Azure Functions Python Library V1' releaseBranchPrefix: 'release' + pythonVersionRequirement: '>=3.10,<3.13' tagPrefix: '' blobPath: 'azure-functions/python/azure-functions' artifactName: 'azure-functions' @@ -134,6 +135,7 @@ extends: libraryVersion: ${{ parameters.V2LibraryVersion }} projectDisplayName: 'Azure Functions Python Library V2' releaseBranchPrefix: 'release' + pythonVersionRequirement: '>=3.13' tagPrefix: '' blobPath: 'azure-functions/python/azure-functions' artifactName: 'azure-functions' \ No newline at end of file diff --git a/eng/ci/official-build.yml b/eng/ci/official-build.yml index b8077fa..14b12db 100644 --- a/eng/ci/official-build.yml +++ b/eng/ci/official-build.yml @@ -53,3 +53,5 @@ extends: dependsOn: Build jobs: - template: /eng/templates/jobs/ci-tests.yml@self + parameters: + poolName: '1es-pool-azfunc' diff --git a/eng/ci/public-build.yml b/eng/ci/public-build.yml index 1a51cf6..fd04fe1 100644 --- a/eng/ci/public-build.yml +++ b/eng/ci/public-build.yml @@ -52,3 +52,5 @@ extends: dependsOn: Build jobs: - template: /eng/templates/jobs/ci-tests.yml@self + parameters: + poolName: '1es-pool-azfunc-public' diff --git a/eng/templates/jobs/build.yml b/eng/templates/jobs/build.yml index b05fda4..9f957d0 100644 --- a/eng/templates/jobs/build.yml +++ b/eng/templates/jobs/build.yml @@ -2,6 +2,11 @@ jobs: - job: "Build" displayName: 'Build Python SDK' + pool: + name: 1es-pool-azfunc-public + image: 1es-ubuntu-22.04 + os: linux + strategy: matrix: Python310: diff --git a/eng/templates/jobs/ci-tests.yml b/eng/templates/jobs/ci-tests.yml index 29323dd..d9bb619 100644 --- a/eng/templates/jobs/ci-tests.yml +++ b/eng/templates/jobs/ci-tests.yml @@ -1,7 +1,17 @@ +parameters: + - name: poolName + type: string + default: '1es-pool-azfunc' + jobs: - job: "TestPython" displayName: "Run Python SDK Unit Tests" + pool: + name: ${{ parameters.poolName }} + image: 1es-ubuntu-22.04 + os: linux + strategy: matrix: python-310: diff --git a/eng/templates/official/release/bump-version.yml b/eng/templates/official/release/bump-version.yml index b26cc60..ea62ea6 100644 --- a/eng/templates/official/release/bump-version.yml +++ b/eng/templates/official/release/bump-version.yml @@ -116,8 +116,19 @@ jobs: if (![string]::IsNullOrWhiteSpace($pythonClassifiers.Trim())) { Write-Host "Updating pyproject Python classifiers" - $classifiersPattern = "(?s)('Programming Language :: Python :: \d\.\d+',\s*)+" - $content = $content -replace $classifiersPattern, "$pythonClassifiers,`n " + # Replace complete version-classifier lines, preserving their indentation + # without consuming whitespace belonging to the following classifier. + $classifiersPattern = "(?m)^(?[ \t]*)'Programming Language :: Python :: \d+\.\d+',?(?:[ \t]*\r?\n[ \t]*'Programming Language :: Python :: \d+\.\d+',?)*" + $newline = if ($content.Contains("`r`n")) { "`r`n" } else { "`n" } + $classifierLines = $pythonClassifiers.Trim() -split '\r?\n' | + Where-Object { ![string]::IsNullOrWhiteSpace($_) } | + ForEach-Object { $_.Trim().TrimEnd(',') + ',' } + $content = [regex]::Replace($content, $classifiersPattern, { + param($match) + ($classifierLines | ForEach-Object { + $match.Groups['indent'].Value + $_ + }) -join $newline + }) } $content | Set-Content -NoNewline $pyprojectPath diff --git a/eng/templates/official/release/publish-release.yml b/eng/templates/official/release/publish-release.yml index bed046f..178ca04 100644 --- a/eng/templates/official/release/publish-release.yml +++ b/eng/templates/official/release/publish-release.yml @@ -1,6 +1,9 @@ parameters: - name: libraryVersion type: string + - name: pythonVersionRequirement + type: string + displayName: 'Python version requirement used to select the worker SDK dependency' - name: projectDisplayName type: string default: 'Azure Functions Python Library' @@ -182,8 +185,95 @@ jobs: notifyUsers: '' instructions: 'Please head to https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}/releases to finish the release note' - - job: PublishRelease + - job: "TestWithWorker" dependsOn: ['CheckGitHubRelease'] + displayName: 'Test with Worker' + steps: + - checkout: none + - pwsh: | + $ErrorActionPreference = 'Stop' + $githubUser = $env:GITHUB_USER + $githubToken = $env:GITHUB_TOKEN + $newLibraryVersion = "${{ parameters.libraryVersion }}" + $pythonVersionRequirement = "${{ parameters.pythonVersionRequirement }}" + $newBranch = "sdk/$newLibraryVersion" + + git config --global user.name "AzureFunctions" + git config --global user.email "azurefunctions@microsoft.com" + $credential = [System.Convert]::ToBase64String( + [System.Text.Encoding]::ASCII.GetBytes("${githubUser}:${githubToken}")) + + git clone "https://${githubUser}:${githubToken}@github.com/Azure/azure-functions-python-worker.git" + if ($LASTEXITCODE -ne 0) { throw 'Failed to clone the worker repository.' } + Set-Location 'azure-functions-python-worker' + git checkout -b $newBranch origin/dev + if ($LASTEXITCODE -ne 0) { throw 'Failed to create the worker SDK branch.' } + + if ($pythonVersionRequirement -eq '>=3.13') { + $pythonMarker = "python_version >= '3.13'" + } elseif ($pythonVersionRequirement -eq '>=3.10,<3.13') { + $pythonMarker = "python_version >= '3.10' and python_version < '3.13'" + } else { + throw "Unsupported Python version requirement: $pythonVersionRequirement" + } + + $projectPath = 'workers/pyproject.toml' + $content = Get-Content -LiteralPath $projectPath -Raw + $dependencyPattern = 'azure-functions==[^;"\r\n]+; ' + [regex]::Escape($pythonMarker) + '(?=")' + if ([regex]::Matches($content, $dependencyPattern).Count -ne 1) { + throw "Expected exactly one worker SDK dependency for $pythonMarker. Update it manually." + } + $content = $content -replace $dependencyPattern, "azure-functions==$newLibraryVersion; $pythonMarker" + [System.IO.File]::WriteAllText((Join-Path $PWD $projectPath), $content) + + git add $projectPath + if ($LASTEXITCODE -ne 0) { throw 'Failed to stage the worker SDK dependency update.' } + git commit -m "build: update Python SDK Version to $newLibraryVersion" + if ($LASTEXITCODE -ne 0) { throw 'Failed to commit the worker SDK dependency update.' } + git push origin $newBranch + if ($LASTEXITCODE -ne 0) { throw 'Failed to push the worker SDK branch.' } + + $headers = @{ + 'Authorization' = "Basic $credential" + 'Accept' = 'application/vnd.github+json' + 'Content-Type' = 'application/json' + 'X-GitHub-Api-Version' = '2022-11-28' + } + $body = @{ + head = $newBranch + base = 'dev' + title = "build: update Python SDK Version to $newLibraryVersion" + body = "Python SDK Version [$newLibraryVersion](https://github.com/${{ parameters.githubOrg }}/${{ parameters.githubRepo }}/releases/tag/${{ parameters.tagPrefix }}$newLibraryVersion)" + draft = $true + maintainer_can_modify = $true + } | ConvertTo-Json -Compress + $response = Invoke-WebRequest -Headers $headers -Method Post -Body $body ` + -Uri 'https://api.github.com/repos/Azure/azure-functions-python-worker/pulls' + if ($response.StatusCode -ne 201) { throw 'Failed to create the worker draft PR.' } + Write-Host "Worker PR draft created: $(($response.Content | ConvertFrom-Json).html_url)" + displayName: 'Create PR in Worker Repo' + # A failed PR attempt must not block manual review or package publication. + continueOnError: true + env: + GITHUB_USER: $(GithubUser) + GITHUB_TOKEN: $(GithubPat) + + - job: "WaitForPythonWorkerPR" + dependsOn: ['TestWithWorker'] + displayName: '(Manual) Check Python Worker PR' + pool: server + steps: + - task: ManualValidation@1 + displayName: 'Check Python Worker PR' + inputs: + notifyUsers: '' + instructions: | + 1. Check the SDK ${{ parameters.libraryVersion }} PR at https://github.com/Azure/azure-functions-python-worker/pulls and confirm its tests pass. + 2. Merge the PR into the worker dev branch when ready. + 3. If automatic PR creation failed, review the TestWithWorker logs and create or update the PR manually, or explicitly approve continuing the release with worker testing deferred. + + - job: PublishRelease + dependsOn: ['WaitForPythonWorkerPR'] displayName: 'Upload artifacts to partner blob for release' pool: