From 3c718ae6b40e0934e64a77e6a277ba50331ed91e Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 20 May 2026 16:44:08 -0600 Subject: [PATCH 1/6] Build + Release pipelines v1 (test) --- eng/ci/official-build.yml | 55 +++++++++++++++++++++++ eng/ci/release.yml | 94 +++++++++++++++++++++++++++++++++++++++ eng/templates/build.yml | 50 +++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 eng/ci/official-build.yml create mode 100644 eng/ci/release.yml create mode 100644 eng/templates/build.yml diff --git a/eng/ci/official-build.yml b/eng/ci/official-build.yml new file mode 100644 index 0000000..429e251 --- /dev/null +++ b/eng/ci/official-build.yml @@ -0,0 +1,55 @@ +variables: + - template: ci/variables/cfs.yml@eng + +trigger: + batch: true + branches: + include: + - main + +# CI only, does not trigger on PRs. +pr: none + +schedules: + # Build nightly to catch any new CVEs and report SDL often. + # We are also required to generate CodeQL reports weekly, so this + # helps us meet that. + - cron: "0 5 * * *" + displayName: Nightly Build + branches: + include: + - main + always: true + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: eng + type: git + name: engineering + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc + image: 1es-ubuntu-22.04 + os: linux + ${{ if eq( variables['Build.Reason'], 'Schedule' ) }}: + demands: + - Priority -equals Low + sdl: + sourceAnalysisPool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + stages: + - stage: BuildAndSign + dependsOn: [] + jobs: + - template: /eng/templates/build.yml@self diff --git a/eng/ci/release.yml b/eng/ci/release.yml new file mode 100644 index 0000000..9b23389 --- /dev/null +++ b/eng/ci/release.yml @@ -0,0 +1,94 @@ +pr: none +trigger: none + +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + pipelines: + - pipeline: DurableTaskPythonBuildPipeline + source: durabletask-python.official + branch: main + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + pool: + name: 1es-pool-azfunc + image: 1es-ubuntu-22.04 + os: linux + + stages: + - stage: release + jobs: + - job: durabletask + displayName: "Release durabletask" + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + pipeline: DurableTaskPythonBuildPipeline + artifactName: drop + targetPath: $(System.DefaultWorkingDirectory)/drop + + steps: + - task: SFP.release-tasks.custom-build-release-task.EsrpRelease@9 + displayName: "ESRP Release durabletask" + inputs: + connectedservicename: "dtfx-internal-esrp-prod" + usemanagedidentity: true + keyvaultname: "durable-esrp-akv" + signcertname: "dts-esrp-cert" + clientid: "0b3ed1a4-0727-4a50-b82a-02c2bd9dec89" + intent: "PackageDistribution" + # DRY-RUN: set to "NPM" while bringing up the pipeline so ESRP + # signs and processes the artifact but does NOT push to PyPI + # (mismatched destination router). Switch back to "PyPi" for + # real releases. See https://aka.ms/python/publish. + contenttype: "NPM" + contentsource: "Folder" + folderlocation: "$(System.DefaultWorkingDirectory)/drop/buildoutputs/durabletask" + waitforreleasecompletion: true + owners: "wangbill@microsoft.com" + approvers: "kaibocai@microsoft.com" + serviceendpointurl: "https://api.esrp.microsoft.com" + mainpublisher: "durabletask-java" + domaintenantid: "33e01921-4d64-4f8c-a055-5bdaffd5e33d" + + - job: durabletask_azuremanaged + displayName: "Release durabletask-azuremanaged" + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + pipeline: DurableTaskPythonBuildPipeline + artifactName: drop + targetPath: $(System.DefaultWorkingDirectory)/drop + + steps: + - task: SFP.release-tasks.custom-build-release-task.EsrpRelease@9 + displayName: "ESRP Release durabletask-azuremanaged" + inputs: + connectedservicename: "dtfx-internal-esrp-prod" + usemanagedidentity: true + keyvaultname: "durable-esrp-akv" + signcertname: "dts-esrp-cert" + clientid: "0b3ed1a4-0727-4a50-b82a-02c2bd9dec89" + intent: "PackageDistribution" + # DRY-RUN: set to "NPM" while bringing up the pipeline so ESRP + # signs and processes the artifact but does NOT push to PyPI + # (mismatched destination router). Switch back to "PyPi" for + # real releases. See https://aka.ms/python/publish. + contenttype: "NPM" + contentsource: "Folder" + folderlocation: "$(System.DefaultWorkingDirectory)/drop/buildoutputs/durabletask-azuremanaged" + waitforreleasecompletion: true + owners: "wangbill@microsoft.com" + approvers: "kaibocai@microsoft.com" + serviceendpointurl: "https://api.esrp.microsoft.com" + mainpublisher: "durabletask-java" + domaintenantid: "33e01921-4d64-4f8c-a055-5bdaffd5e33d" diff --git a/eng/templates/build.yml b/eng/templates/build.yml new file mode 100644 index 0000000..9b042f6 --- /dev/null +++ b/eng/templates/build.yml @@ -0,0 +1,50 @@ +jobs: + - job: + templateContext: + outputs: + - output: pipelineArtifact + path: $(Build.ArtifactStagingDirectory) + artifact: drop + sbomBuildDropPath: "$(System.DefaultWorkingDirectory)" + sbomPackageName: "Durable Task Python SBOM" + + steps: + - checkout: self + + - task: UsePythonVersion@0 + displayName: "Use Python 3.12" + inputs: + versionSpec: "3.12" + addToPath: true + + # Install build + lint tooling + - script: | + python -m pip install --upgrade pip + python -m pip install build flake8 + displayName: "Install build tooling" + + # Lint core SDK + - script: flake8 . + displayName: "flake8: durabletask" + workingDirectory: durabletask + + # Lint azuremanaged provider + - script: flake8 . + displayName: "flake8: durabletask-azuremanaged" + workingDirectory: durabletask-azuremanaged + + # Build sdist + wheel for durabletask (core SDK) + - script: | + python -m build --sdist --wheel --outdir $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask . + displayName: "Build durabletask (sdist + wheel)" + + # Build sdist + wheel for durabletask-azuremanaged + - script: | + python -m build --sdist --wheel --outdir $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask-azuremanaged ./durabletask-azuremanaged + displayName: "Build durabletask-azuremanaged (sdist + wheel)" + + # List staged outputs for visibility in logs + - script: | + ls -la $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask + ls -la $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask-azuremanaged + displayName: "List build outputs" From d3c298454af0327ae9e4e8ee2ea260b2e9b70c41 Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 20 May 2026 16:51:51 -0600 Subject: [PATCH 2/6] Pip auth --- eng/templates/build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eng/templates/build.yml b/eng/templates/build.yml index 9b042f6..952bd2c 100644 --- a/eng/templates/build.yml +++ b/eng/templates/build.yml @@ -17,6 +17,13 @@ jobs: versionSpec: "3.12" addToPath: true + # The 1ES pool is network-isolated, so direct pypi.org access is blocked. + # Authenticate pip to an ADO Artifacts feed that proxies PyPI as upstream. + - task: PipAuthenticate@1 + displayName: "Pip Authenticate" + inputs: + artifactFeeds: "internal/PythonSDK_Internal_PublicPackages" + # Install build + lint tooling - script: | python -m pip install --upgrade pip From 67c5b93056f3971a367564bd08ddfc2b5685b996 Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 20 May 2026 17:07:42 -0600 Subject: [PATCH 3/6] Loosen filter for test --- eng/ci/release.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eng/ci/release.yml b/eng/ci/release.yml index 9b23389..7b963a5 100644 --- a/eng/ci/release.yml +++ b/eng/ci/release.yml @@ -10,7 +10,10 @@ resources: pipelines: - pipeline: DurableTaskPythonBuildPipeline source: durabletask-python.official - branch: main + # NOTE: `branch:` is intentionally omitted during bring-up so the release + # can pull the latest successful build from any branch. Once this is + # merged to main and the official build has run there, restore + # `branch: main` so only main builds are releasable. extends: template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates From e4e66fa503e9e6eada7aa49d153fc544904a486e Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 20 May 2026 17:17:50 -0600 Subject: [PATCH 4/6] Bump versions, revert testing changes --- CHANGELOG.md | 2 ++ durabletask-azuremanaged/CHANGELOG.md | 3 +++ durabletask-azuremanaged/pyproject.toml | 4 ++-- eng/ci/release.yml | 20 ++++++-------------- pyproject.toml | 2 +- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1c2f5..bca5a28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +## v1.5.0 + ADDED - Added `ReplaySafeLogger` and `OrchestrationContext.create_replay_safe_logger()` diff --git a/durabletask-azuremanaged/CHANGELOG.md b/durabletask-azuremanaged/CHANGELOG.md index 2a416c3..8a74350 100644 --- a/durabletask-azuremanaged/CHANGELOG.md +++ b/durabletask-azuremanaged/CHANGELOG.md @@ -7,6 +7,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +## v1.5.0 + +- Updates base dependency to durabletask v1.5.0 - Added optional `interceptors`, `channel`, and `channel_options` parameters to `DurableTaskSchedulerClient`, `AsyncDurableTaskSchedulerClient`, and `DurableTaskSchedulerWorker` to allow combining custom gRPC interceptors with diff --git a/durabletask-azuremanaged/pyproject.toml b/durabletask-azuremanaged/pyproject.toml index ee23588..016e9ff 100644 --- a/durabletask-azuremanaged/pyproject.toml +++ b/durabletask-azuremanaged/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta" [project] name = "durabletask.azuremanaged" -version = "1.4.0" +version = "1.5.0" description = "Durable Task Python SDK provider implementation for the Azure Durable Task Scheduler" keywords = [ "durable", @@ -26,7 +26,7 @@ requires-python = ">=3.10" license = {file = "LICENSE"} readme = "README.md" dependencies = [ - "durabletask>=1.4.0", + "durabletask>=1.5.0", "azure-identity>=1.19.0" ] diff --git a/eng/ci/release.yml b/eng/ci/release.yml index 7b963a5..5cd3c18 100644 --- a/eng/ci/release.yml +++ b/eng/ci/release.yml @@ -47,16 +47,12 @@ extends: signcertname: "dts-esrp-cert" clientid: "0b3ed1a4-0727-4a50-b82a-02c2bd9dec89" intent: "PackageDistribution" - # DRY-RUN: set to "NPM" while bringing up the pipeline so ESRP - # signs and processes the artifact but does NOT push to PyPI - # (mismatched destination router). Switch back to "PyPi" for - # real releases. See https://aka.ms/python/publish. - contenttype: "NPM" + contenttype: "PyPi" contentsource: "Folder" folderlocation: "$(System.DefaultWorkingDirectory)/drop/buildoutputs/durabletask" waitforreleasecompletion: true - owners: "wangbill@microsoft.com" - approvers: "kaibocai@microsoft.com" + owners: "torosent@microsoft.com" + approvers: "andystaples@microsoft.com;beverst@microsoft.com" serviceendpointurl: "https://api.esrp.microsoft.com" mainpublisher: "durabletask-java" domaintenantid: "33e01921-4d64-4f8c-a055-5bdaffd5e33d" @@ -82,16 +78,12 @@ extends: signcertname: "dts-esrp-cert" clientid: "0b3ed1a4-0727-4a50-b82a-02c2bd9dec89" intent: "PackageDistribution" - # DRY-RUN: set to "NPM" while bringing up the pipeline so ESRP - # signs and processes the artifact but does NOT push to PyPI - # (mismatched destination router). Switch back to "PyPi" for - # real releases. See https://aka.ms/python/publish. - contenttype: "NPM" + contenttype: "PyPi" contentsource: "Folder" folderlocation: "$(System.DefaultWorkingDirectory)/drop/buildoutputs/durabletask-azuremanaged" waitforreleasecompletion: true - owners: "wangbill@microsoft.com" - approvers: "kaibocai@microsoft.com" + owners: "torosent@microsoft.com" + approvers: "andystaples@microsoft.com;beverst@microsoft.com" serviceendpointurl: "https://api.esrp.microsoft.com" mainpublisher: "durabletask-java" domaintenantid: "33e01921-4d64-4f8c-a055-5bdaffd5e33d" diff --git a/pyproject.toml b/pyproject.toml index 145b930..731b988 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta" [project] name = "durabletask" -version = "1.4.0" +version = "1.5.0" description = "A Durable Task Client SDK for Python" keywords = [ "durable", From 6257598490ace3519d82b9c77c1e54848fdf3e16 Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 20 May 2026 17:20:17 -0600 Subject: [PATCH 5/6] Remove old comment --- eng/ci/release.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/eng/ci/release.yml b/eng/ci/release.yml index 5cd3c18..a5c9764 100644 --- a/eng/ci/release.yml +++ b/eng/ci/release.yml @@ -10,10 +10,6 @@ resources: pipelines: - pipeline: DurableTaskPythonBuildPipeline source: durabletask-python.official - # NOTE: `branch:` is intentionally omitted during bring-up so the release - # can pull the latest successful build from any branch. Once this is - # merged to main and the official build has run there, restore - # `branch: main` so only main builds are releasable. extends: template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates From 628048dc5c74b6738ead11dbdb9f10e26870cfbb Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Thu, 21 May 2026 14:40:43 -0600 Subject: [PATCH 6/6] PR feedback --- durabletask-azuremanaged/pyproject.toml | 2 +- eng/ci/release.yml | 13 +++++++---- eng/templates/build.yml | 29 ++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/durabletask-azuremanaged/pyproject.toml b/durabletask-azuremanaged/pyproject.toml index 016e9ff..e5e2b0b 100644 --- a/durabletask-azuremanaged/pyproject.toml +++ b/durabletask-azuremanaged/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ [project.optional-dependencies] azure-blob-payloads = [ - "durabletask[azure-blob-payloads]>=1.4.0" + "durabletask[azure-blob-payloads]>=1.5.0" ] [project.urls] diff --git a/eng/ci/release.yml b/eng/ci/release.yml index a5c9764..0bd8a52 100644 --- a/eng/ci/release.yml +++ b/eng/ci/release.yml @@ -47,8 +47,13 @@ extends: contentsource: "Folder" folderlocation: "$(System.DefaultWorkingDirectory)/drop/buildoutputs/durabletask" waitforreleasecompletion: true - owners: "torosent@microsoft.com" - approvers: "andystaples@microsoft.com;beverst@microsoft.com" + # Auto-populate from the build queuer's identity so we don't + # hardcode personal emails in source. ESRP will send the + # release notification / approval link to whoever clicked + # "Run pipeline". This matches the pattern used by + # Azure/azure-sdk-for-python and microsoft/mcp pipelines. + owners: $(Build.RequestedForEmail) + approvers: $(Build.RequestedForEmail) serviceendpointurl: "https://api.esrp.microsoft.com" mainpublisher: "durabletask-java" domaintenantid: "33e01921-4d64-4f8c-a055-5bdaffd5e33d" @@ -78,8 +83,8 @@ extends: contentsource: "Folder" folderlocation: "$(System.DefaultWorkingDirectory)/drop/buildoutputs/durabletask-azuremanaged" waitforreleasecompletion: true - owners: "torosent@microsoft.com" - approvers: "andystaples@microsoft.com;beverst@microsoft.com" + owners: $(Build.RequestedForEmail) + approvers: $(Build.RequestedForEmail) serviceendpointurl: "https://api.esrp.microsoft.com" mainpublisher: "durabletask-java" domaintenantid: "33e01921-4d64-4f8c-a055-5bdaffd5e33d" diff --git a/eng/templates/build.yml b/eng/templates/build.yml index 952bd2c..0b9b393 100644 --- a/eng/templates/build.yml +++ b/eng/templates/build.yml @@ -1,5 +1,6 @@ jobs: - - job: + - job: BuildAndSign + displayName: "Build and sign" templateContext: outputs: - output: pipelineArtifact @@ -24,10 +25,10 @@ jobs: inputs: artifactFeeds: "internal/PythonSDK_Internal_PublicPackages" - # Install build + lint tooling + # Install build + lint + test tooling - script: | python -m pip install --upgrade pip - python -m pip install build flake8 + python -m pip install build flake8 pytest pytest-asyncio aiohttp displayName: "Install build tooling" # Lint core SDK @@ -55,3 +56,25 @@ jobs: ls -la $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask ls -la $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask-azuremanaged displayName: "List build outputs" + + # Install the built wheels and run unit tests against them. We exclude + # tests marked `dts` (require the Durable Task Scheduler emulator) and + # `azurite` (require the Azurite blob emulator) since those external + # services aren't provisioned in this network-isolated pool. The full + # matrix (including emulator-backed tests) runs in GitHub Actions on + # PRs to main and main itself; this step is defense-in-depth to ensure + # the artifacts we're about to ship are at least importable and pass + # the pure-Python unit tests. + - script: | + set -e + python -m pip install $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask/*.whl + python -m pip install $(Build.ArtifactStagingDirectory)/buildoutputs/durabletask-azuremanaged/*.whl + displayName: "Install built wheels" + + - script: pytest -m "not dts and not azurite" --verbose + displayName: "pytest: durabletask (unit tests, no emulators)" + workingDirectory: tests/durabletask + + - script: pytest -m "not dts" --verbose + displayName: "pytest: durabletask-azuremanaged (unit tests, no emulators)" + workingDirectory: tests/durabletask-azuremanaged