diff --git a/eng/ci/worker-release.yml b/eng/ci/worker-release.yml new file mode 100644 index 00000000..c0ce2953 --- /dev/null +++ b/eng/ci/worker-release.yml @@ -0,0 +1,33 @@ +pr: none + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: eng + type: git + name: engineering + ref: refs/tags/release + +variables: + - name: codeql.excludePathPatterns + value: deps/,build/ + +extends: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + sdl: + codeSignValidation: + enabled: true + break: true + + stages: + - stage: Release + jobs: + - template: /eng/templates/official/jobs/publish-release.yml@self diff --git a/eng/templates/official/jobs/publish-release.yml b/eng/templates/official/jobs/publish-release.yml new file mode 100644 index 00000000..522fcdc6 --- /dev/null +++ b/eng/templates/official/jobs/publish-release.yml @@ -0,0 +1,386 @@ +jobs: + +- job: "CreateReleaseBranch" + displayName: 'Create Release Branch' + pool: + name: 1es-pool-azfunc + image: 1es-ubuntu-22.04 + os: linux + steps: + - powershell: | + $githubToken = "$(GithubPat)" + $newWorkerVersion = "$(NewWorkerVersion)" + $versionFile = "azure_functions_worker/version.py" + + if($newWorkerVersion -match '(\d)+.(\d)+.(\d)+') { + # Create GitHub credential + git config --global user.name "AzureFunctionsPython" + git config --global user.email "azfunc@microsoft.com" + + # Heading to Artifact Repository + Write-Host "Operating based on $stagingDirectory/azure-functions-python-worker" + git checkout -b "release/$newWorkerVersion" + + # Change azure_functions_worker/version.py version + Write-Host "Change version number in version.py to $newWorkerVersion" + ((Get-Content $versionFile) -replace "VERSION = '(\d+).(\d+).*'", "VERSION = '$newWorkerVersion'" -join "`n") + "`n" | Set-Content -NoNewline $versionFile + git add $versionFile + git commit -m "build: update Python Worker Version to $newWorkerVersion" + + # Create release branch release/X.Y.Z + Write-Host "Creating release branch release/$newWorkerVersion" + git push --repo="https://$githubToken@github.com/Azure/azure-functions-python-worker.git" + } else { + Write-Host "NewWorkerVersion $newWorkerVersion is malformed (example: 1.1.8)" + exit -1 + } + displayName: 'Push release/x.y.z' + +- job: "CheckReleaseBranch" + dependsOn: ['CreateReleaseBranch'] + displayName: '(Manual) Check Release Branch' + pool: server + steps: + - task: ManualValidation@1 + displayName: '(Optional) Modify release/x.y.z branch' + inputs: + notifyUsers: '' # No email notifications sent + instructions: | + 1. Check if the https://github.com/Azure/azure-functions-python-worker/tree/release/$(NewWorkerVersion) passes all unit tests. + 2. If not, modify the release/$(NewWorkerVersion) branch. + 3. Ensure release/$(NewWorkerVersion) branch contains all necessary changes since it will be propagated to v4 workers. + +- job: "CreateReleaseTag" + dependsOn: ['CheckReleaseBranch'] + steps: + - powershell: | + $githubToken = "$(GithubPat)" + $newWorkerVersion = "$(NewWorkerVersion)" + + if($newWorkerVersion -match '(\d)+.(\d)+.(\d)+') { + # Create GitHub credential + git config --global user.name "AzureFunctionsPython" + git config --global user.email "funcdisc@microsoft.com" + + # Clone Repository + git clone https://$githubToken@github.com/Azure/azure-functions-python-worker + Write-Host "Cloned azure-functions-python-worker into local" + Set-Location "azure-functions-python-worker" + git checkout "origin/release/$newWorkerVersion" + + # Create release tag X.Y.Z + Write-Host "Creating release tag $newWorkerVersion" + git tag -a "$newWorkerVersion" -m "$newWorkerVersion" + + # Push tag to remote + git push origin $newWorkerVersion + } else { + Write-Host "NewWorkerVersion $newWorkerVersion is malformed (example: 1.1.8)" + exit -1 + } + displayName: 'Create and push release tag x.y.z' + - powershell: | + $githubUser = "$(GithubUser)" + $githubToken = "$(GithubPat)" + $newWorkerVersion = "$(NewWorkerVersion)" + + if($newWorkerVersion -match '(\d)+.(\d)+.(\d)+') { + # Create GitHub credential + $credential = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${githubUser}:${githubToken}")) + + # Create Release Note + Write-Host "Creating release note in GitHub" + $body = (@{tag_name="$newWorkerVersion";name="Release $newWorkerVersion";body="- Fill in Release Note Here";draft=$true} | ConvertTo-Json -Compress) + $response = Invoke-WebRequest -Headers @{"Cache-Control"="no-cache";"Content-Type"="application/json";"Authorization"="Basic $credential"} -Method Post -Body "$body" -Uri "https://api.github.com/repos/Azure/azure-functions-python-worker/releases" + + # Return Value + if ($response.StatusCode -ne 201) { + Write-Host "Failed to create release note in GitHub" + exit -1 + } + + $draftUrl = $response | ConvertFrom-Json | Select -expand url + Write-Host "Release draft created in $draftUrl" + } else { + Write-Host "NewWorkerVersion $newWorkerVersion is malformed (example: 1.1.8)" + exit -1 + } + displayName: 'Create GitHub release draft' + +- job: "CheckGitHubRelease" + dependsOn: ['CreateReleaseTag'] + displayName: '(Manual) Check GitHub release note' + pool: server + steps: + - task: ManualValidation@1 + displayName: 'Write GitHub release note' + inputs: + notifyUsers: '' + instructions: 'Please head to https://github.com/Azure/azure-functions-python-worker/releases to finish the release note' + +- job: "WaitForPythonWorkerBuild" + dependsOn: ['CheckGitHubRelease'] + displayName: '(Manual) Wait For Python Worker Build' + pool: server + steps: + - task: ManualValidation@1 + displayName: 'Wait For Python Worker Build' + inputs: + notifyUsers: '' + instructions: 'Ensure the build of release/4.x.y.z finishes in https://dev.azure.com/azfunc/internal/_build?definitionId=652 and verify if PackageWorkers task is completed.' + + +- job: "PublishNuget" + dependsOn: ['WaitForPythonWorkerBuild'] + displayName: 'Publish Nuget' + templateContext: + outputs: + - output: nuget + packagesToPush: '$(Pipeline.Workspace)/PythonWorkerArtifact/**/*.nupkg;!$(Pipeline.Workspace)/PythonWorkerArtifact/**/*.symbols.nupkg' + publishVstsFeed: 'e6a70c92-4128-439f-8012-382fe78d6396/eb652719-f36a-4e78-8541-e13a3cd655f9' + allowPackageConflicts: true + packageParentPath: '$(Pipeline.Workspace)' + steps: + - task: DownloadPipelineArtifact@2 + displayName: 'Download Python Worker release/4.x.y.z Artifact' + inputs: + buildType: specific + project: '3f99e810-c336-441f-8892-84983093ad7f' + definition: 652 + specificBuildWithTriggering: true + buildVersionToDownload: latestFromBranch + branchName: 'refs/heads/release/$(NewWorkerVersion)' + allowPartiallySucceededBuilds: true + allowFailedBuilds: true + targetPath: '$(Pipeline.Workspace)/PythonWorkerArtifact' + + +- job: "CheckNugetPackageContent" + dependsOn: ['PublishNuget'] + displayName: '(Manual) Check Nuget Package Content' + pool: server + steps: + - task: ManualValidation@1 + displayName: 'Check nuget package content' + inputs: + notifyUsers: '' + instructions: | + Please check the latest release package at + https://azfunc.visualstudio.com/Azure%20Functions/_artifacts/feed/AzureFunctionsRelease/NuGet/Microsoft.Azure.Functions.PythonWorker/overview + +- job: "HostRepoPRs" + dependsOn: ['CheckNugetPackageContent'] + displayName: 'Create Host PRs' + steps: + - powershell: | + $githubUser = "$(GithubUser)" + $githubToken = "$(GithubPat)" + $newWorkerVersion = "$(NewWorkerVersion)" + $newBranch = "python/$newWorkerVersion" + + if($newWorkerVersion -match '(\d)+.(\d)+.(\d)+') { + # Create GitHub credential + git config --global user.name "AzureFunctionsPython" + git config --global user.email "funcdisc@microsoft.com" + + # Create GitHub credential + $credential = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${githubUser}:${githubToken}")) + + # Clone Repository + git clone https://$githubToken@github.com/Azure/azure-functions-host + Write-Host "Cloned azure-functions-host into local and checkout $newBranch branch" + Set-Location "azure-functions-host" + git checkout -b $newBranch "origin/dev" + + # Modify Python Worker Version in eng\build\python.props + Write-Host "Replacing eng\build\python.props" + ((Get-Content eng\build\Workers.Python.props) -replace "PythonWorker`" Version=`"(\d)+.(\d)+.(\d)+.?(\d)*`"","PythonWorker`" Version=`"$newWorkerVersion`"" -join "`n") +"`n" | Set-Content -NoNewline eng\build\Workers.Python.props + + # Modify Python Worker Version in test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj + Write-Host "Replacing test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj" + ((Get-Content test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj) -replace "PythonWorker`" Version=`"(\d)+.(\d)+.(\d)+.?(\d)*`"","PythonWorker`" Version=`"$newWorkerVersion`"" -join "`n") + "`n" | Set-Content -NoNewline test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj + + # Modify release_notes.md + Write-Host "Adding a new entry in release_note.md" + ((Get-Content release_notes.md) -replace "-->","$&`n- Update Python Worker Version to [$newWorkerVersion](https://github.com/Azure/azure-functions-python-worker/releases/tag/$newWorkerVersion)" -join "`n") + "`n" | Set-Content -NoNewline release_notes.md + + # Commit Python Version + Write-Host "Pushing $newBranch to host repo" + git add eng\build\Workers.Python.props + git add test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj + git add release_notes.md + git commit -m "Update Python Worker Version to $newWorkerVersion" + git push origin $newBranch + + # Create PR + Write-Host "Creating PR draft in GitHub" + $prTemplateContent = @" + ### Issue describing the changes in this PR + + Update Python Worker Version to $newWorkerVersion + + Python Worker Release note [$newWorkerVersion](https://github.com/Azure/azure-functions-python-worker/releases/tag/$newWorkerVersion) + + ### Pull request checklist + + **IMPORTANT**: Currently, changes must be backported to the `in-proc` branch to be included in Core Tools and non-Flex deployments. + + * [ ] Backporting to the `in-proc` branch is not required + * [x]Otherwise: Link to backporting PR + * [x] My changes **do not** require documentation changes + * [ ] Otherwise: Documentation issue linked to PR + * [ ] My changes **should not** be added to the release notes for the next release + * [x] Otherwise: I've added my notes to `release_notes.md` + * [x] My changes **do not** need to be backported to a previous version + * [ ] Otherwise: Backport tracked by issue/PR #issue_or_pr + * [x] My changes **do not** require diagnostic events changes + * Otherwise: I have added/updated all related diagnostic events and their documentation (Documentation issue linked to PR) + * [x] I have added all required tests (Unit tests, E2E tests) + + "@ + + $body = (@{head="$newBranch";base="dev";body=$prTemplateContent;draft=$true;maintainer_can_modify=$true;title="Update Python Worker Version to $newWorkerVersion"} | ConvertTo-Json -Compress)$response = Invoke-WebRequest -Headers @{"Cache-Control"="no-cache";"Content-Type"="application/json";"Authorization"="Basic $credential";"Accept"="application/vnd.github.v3+json"} -Method Post -Body "$body" -Uri "https://api.github.com/repos/Azure/azure-functions-host/pulls" + + # Return Value + if ($response.StatusCode -ne 201) { + Write-Host "Failed to create a PR in Azure Functions Host" + exit -1 + } + + $draftUrl = $response | ConvertFrom-Json | Select -expand url + Write-Host "PR draft created in $draftUrl" + } else { + Write-Host "NewWorkerVersion $newWorkerVersion is malformed (example: 1.1.8)" + exit -1 + } + displayName: 'Create Host PR for dev' + - powershell: | + $githubUser = "$(GithubUser)" + $githubToken = "$(GithubPat)" + $newWorkerVersion = "$(NewWorkerVersion)" + $newBranch = "python/$newWorkerVersion" + + if($newWorkerVersion -match '(\d)+.(\d)+.(\d)+') { + # Create GitHub credential + git config --global user.name "AzureFunctionsPython" + git config --global user.email "funcdisc@microsoft.com" + + # Create GitHub credential + $credential = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${githubUser}:${githubToken}")) + + # Clone Repository + git clone https://$githubToken@github.com/Azure/azure-functions-host + Write-Host "Cloned azure-functions-host into local and checkout $newBranch branch" + Set-Location "azure-functions-host" + git checkout -b backport/$newBranch "origin/in-proc" + + # Modify Python Worker Version in eng\build\python.props + Write-Host "Replacing eng\build\python.props" + ((Get-Content eng\build\Workers.Python.props) -replace "PythonWorker`" Version=`"(\d)+.(\d)+.(\d)+.?(\d)*`"","PythonWorker`" Version=`"$newWorkerVersion`"" -join "`n") +"`n" | Set-Content -NoNewline eng\build\Workers.Python.props + + # Modify Python Worker Version in test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj + Write-Host "Replacing test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj" + ((Get-Content test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj) -replace "PythonWorker`" Version=`"(\d)+.(\d)+.(\d)+.?(\d)*`"","PythonWorker`" Version=`"$newWorkerVersion`"" -join "`n") + "`n" | Set-Content -NoNewline test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj + + # Modify release_notes.md + Write-Host "Adding a new entry in release_note.md" + ((Get-Content release_notes.md) -replace "-->","$&`n- Update Python Worker Version to [$newWorkerVersion](https://github.com/Azure/azure-functions-python-worker/releases/tag/$newWorkerVersion)" -join "`n") + "`n" | Set-Content -NoNewline release_notes.md + + # Commit Python Version + Write-Host "Pushing $newBranch to host repo" + git add eng\build\Workers.Python.props + git add test\WebJobs.Script.Tests\WebJobs.Script.Tests.csproj + git add release_notes.md + git commit -m "[Backport] Update Python Worker Version to $newWorkerVersion" + git push origin $newBranch + + # Create PR + Write-Host "Creating PR draft in GitHub" + $prTemplateContent = @" + ### Issue describing the changes in this PR + + [Backport] Update Python Worker Version to $newWorkerVersion + + Python Worker Release note [$newWorkerVersion](https://github.com/Azure/azure-functions-python-worker/releases/tag/$newWorkerVersion) + + ### Pull request checklist + + **IMPORTANT**: Currently, changes must be backported to the `in-proc` branch to be included in Core Tools and non-Flex deployments. + + * [ ] Backporting to the `in-proc` branch is not required + * [ ]Otherwise: Link to backporting PR + * [x] My changes **do not** require documentation changes + * [ ] Otherwise: Documentation issue linked to PR + * [ ] My changes **should not** be added to the release notes for the next release + * [x] Otherwise: I've added my notes to `release_notes.md` + * [x] My changes **do not** need to be backported to a previous version + * [ ] Otherwise: Backport tracked by issue/PR #issue_or_pr + * [x] My changes **do not** require diagnostic events changes + * Otherwise: I have added/updated all related diagnostic events and their documentation (Documentation issue linked to PR) + * [x] I have added all required tests (Unit tests, E2E tests) + + "@ + + $body = (@{head="$newBranch";base="in-proc";body=$prTemplateContent;draft=$true;maintainer_can_modify=$true;title="Update Python Worker Version to $newWorkerVersion"} | ConvertTo-Json -Compress)$response = Invoke-WebRequest -Headers @{"Cache-Control"="no-cache";"Content-Type"="application/json";"Authorization"="Basic $credential";"Accept"="application/vnd.github.v3+json"} -Method Post -Body "$body" -Uri "https://api.github.com/repos/Azure/azure-functions-host/pulls" + + # Return Value + if ($response.StatusCode -ne 201) { + Write-Host "Failed to create a PR in Azure Functions Host" + exit -1 + } + + $draftUrl = $response | ConvertFrom-Json | Select -expand url + Write-Host "PR draft created in $draftUrl" + } else { + Write-Host "NewWorkerVersion $newWorkerVersion is malformed (example: 1.1.8)" + exit -1 + } + displayName: 'Create Host PR for in-proc' + +- job: "CheckHostPRs" + dependsOn: ['HostRepoPRs'] + displayName: '(Manual) Check Host PRs' + pool: server + steps: + - task: ManualValidation@1 + displayName: 'Finish Host PRs' + inputs: + notifyUsers: '' + instructions: | + Go to https://github.com/Azure/azure-functions-host/pulls and finish the host v4 PR. + If the content misses something, checkout "python/x.y.z" from remote and make new commits to it. + +- job: "MergeToMainAndDev" + dependsOn: ['CheckHostPRs'] + displayName: 'Merge release/x.y.z back to main & dev' + steps: + - powershell: | + $githubToken = "$(GithubPat)" + $newWorkerVersion = "$(NewWorkerVersion)" + + if($newWorkerVersion -match '(\d)+.(\d)+.(\d)+') { + # Create GitHub credential + git config --global user.name "AzureFunctionsPython" + git config --global user.email "funcdisc@microsoft.com" + + # Clone Repository + git clone https://$githubToken@github.com/Azure/azure-functions-python-worker + Write-Host "Cloned azure-functions-python-worker into local" + Set-Location "azure-functions-python-worker" + + # Merge back to main + Write-Host "Merging release/$newWorkerVersion back to main" + git checkout main + git merge "origin/release/$newWorkerVersion" + git push origin main + + # Merge back to dev + Write-Host "Merging release/$newWorkerVersion back to dev" + git checkout dev + git merge "origin/release/$newWorkerVersion" + git push origin dev + } else { + Write-Host "NewWorkerVersion $newWorkerVersion is malformed (example: 1.1.8)" + exit -1 + } + displayName: 'Merge release/x.y.z back to main & dev'