How to ship a new version of msal to PyPI. Everything happens in Azure DevOps
(no GitHub Releases, no Git-tag-triggered automation).
Confirm these are set up in ADO (IdentityDivision → IDDP project) — the
release will fail at runtime if any are missing:
- Pipeline MSAL.Python-Publish (definition
3067) exists - Service connection
MSAL-ESRP-AMEexists and is authorized - Environment
MSAL-Python-Releasehas a required manual approval configured under Approvals and checks - Key Vault
MSALVaultcontains certMSAL-ESRP-Release-Signing
Note on TestPyPI: The TestPyPI publish path (
publishTarget = test.pypi.org (Preview / RC)) is currently a no-op — theMSAL-Test-Python-Uploadservice connection has not been created yet, so that stage prints a skip message and uploads nothing. Until it's wired up, use an RC version (e.g.1.36.0rc1) on the production path for dry runs.
The package version lives in one file: msal/sku.py.
__version__ = "1.36.0" # final release
# or
__version__ = "1.36.0rc1" # RC / dry runOpen a PR, get it merged into dev.
git checkout dev && git pull
git checkout -b release-1.36.0
git push origin release-1.36.0Pushing the branch does not publish anything — the pipeline is manual.
ADO → IDDP → MSAL.Python-Publish (3067) → Run pipeline:
| Field | Value |
|---|---|
| Branch | release-1.36.0 |
| Package version to publish | 1.36.0 (must match msal/sku.py exactly) |
| Publish target | pypi.org (ESRP Production) |
The pipeline runs:
PreBuildCheck → Validate → UnitTests → E2ETests → Build → PublishPyPI
When PublishPyPI starts, it pauses for approval on the
MSAL-Python-Release environment. An approver clicks Approve in
ADO → Pipelines → Environments → MSAL-Python-Release.
ESRP signs the artifact and uploads to PyPI. Verify:
- https://pypi.org/project/msal/
pip install msal==1.36.0
Recommended flow to exercise the pipeline end-to-end without burning a real version number:
- Set
msal/sku.pyto an RC version:__version__ = "1.36.0rc1" - Open a PR, merge to
dev - Cut
release-1.36.0fromdev - Queue MSAL.Python-Publish:
- Package version:
1.36.0rc1 - Publish target:
pypi.org (ESRP Production)
- Package version:
- Approve when prompted
- Confirm
pip install msal==1.36.0rc1 --preworks - Then bump to
1.36.0and run the real release
RC versions are not installed by default by pip install msal (they require
--pre), so they're safe to push to production PyPI for verification.
# Fix on dev first
git checkout dev
# ...PR, merge fix into dev...
# Merge into the existing release branch
git checkout release-1.36.0
git merge dev
# Bump patch version in msal/sku.py: 1.36.0 → 1.36.1
git commit -am "bump to 1.36.1"
git push origin release-1.36.0Then re-queue MSAL.Python-Publish with packageVersion = 1.36.1 and
pypi.org (ESRP Production). Approve.
| Old (GitHub-Actions) | New (ADO) |
|---|---|
Push to release-* auto-published to TestPyPI |
Manual queue with test.pypi.org target (currently no-op) |
| Push a Git tag auto-published to PyPI | Manual queue with pypi.org (ESRP Production) target |
PYPI_API_TOKEN GitHub secret |
ESRP service connection MSAL-ESRP-AME |
| Anyone with tag-push could ship | Required approver on MSAL-Python-Release environment |
Git tags are still allowed for source-tracking, but they trigger nothing.
See .Pipelines/CI-AND-RELEASE-PIPELINES.md for stage-by-stage detail, triggers, and the shared template structure.