You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Partner teams developing first-party extensions regularly need to share a build from an unmerged branch with a customer or internal tester. Today that means either manually running azd x pack --bundle and sending a .zip around, or running the release pipeline against a feature branch, which has release-blocking side effects (#9408). This proposes building an extension bundle automatically for every PR that touches an extension, publishing it to Azure Storage, and posting install instructions as a PR comment.
Motivation
The scenario that prompted this: a team needed to share RLE changes that had not yet merged with a 1P customer. The bundle .zip flow works but was described as noticeably less convenient than an install command, and the release-pipeline workaround created a release and tag from a branch.
Proposal
Mirror the existing CLI PR build pattern rather than inventing a new one. eng/pipelines/templates/stages/publish.yml already has all the moving parts:
A Publish_For_PR deployment job with environment: none and isProduction: false, conditioned on Build.Reason being PullRequest.
Upload to a PR-scoped storage path (pr/$(PRNumber)).
eng/pipelines/templates/steps/update-prcomment.yml keyed on an HTML comment tag, so the comment is updated in place instead of a new comment per push.
Applied to extensions:
Build the all-in-one bundle via azd x pack --bundle and upload it to azd/extensions/pr/<PRNumber>/.
Use a stable per-PR URL, overwritten on each push, the same always-latest approach the nightly storage folder uses. The reviewer or customer keeps one URL for the life of the PR and re-runs the same command to pick up the newest build.
Post or update a single PR comment with the install command, the extension version, the commit SHA, and clear "unsigned development build, not an official release" wording.
Because the bundle contains every platform's artifacts, the comment is one command for all platforms, unlike the CLI PR comment which lists seven platform-specific URLs.
Why a bundle and not a per-PR registry.json
A per-PR registry.json would make azd extension source add plus azd extension install work and would enable azd extension upgrade, but it leaves durable state on the user's machine, and that state becomes actively harmful once the PR artifacts are pruned.
Extension source resolution has no failover. In pkg/extensions/manager.go, a source that fails to list returns immediately:
sourceExtensions, err:=source.ListExtensions(ctx)
iferr!=nil {
returnnil, fmt.Errorf("unable to list extension: %w", err)
}
So a single stale PR source whose blob has expired breaks azd extension list --available, azd extension install for unrelated extensions, and azd extension upgrade, until the user works out which source to remove. Anyone who tried a few PR builds would accumulate several of these. The documented "unreachable dev source blocks all operations" behavior is the same failure mode.
Bundle installs leave no durable source: the transient source is removed after install and the extension is re-pointed at the reserved bundle source. That property is what makes PR-scoped artifacts safe to delete later.
Version identity
PR builds should not be published as the plain manifest version, or azd extension list cannot distinguish a PR build from a real release. Reuse the approach in eng/scripts/Set-ExtensionVersionVariable.ps1, which appends a semver-valid prerelease suffix for nightly builds.
Known wrinkle worth documenting rather than solving here: appending a suffix to an already-prerelease base (0.2.0-preview becomes 0.2.0-preview.pr.<n>.<buildid>) sorts above0.2.0-preview under semver precedence, so a user on a PR build is not automatically superseded by the matching release. This is the same caveat already documented for nightly prerelease bases.
Retention
PR artifacts should expire. An Azure Storage lifecycle rule on the pr/ prefix is preferable to bespoke pipeline cleanup: it cannot silently fail and it can cover the existing CLI PR builds under azd/standalone/pr/ at the same time. With the bundle approach, expiry only invalidates an old link and cannot break a user's extension setup.
This is distinct from #9177, which covers pruning entries from the nightly, dev, and prod registries.
Dependencies and open questions
Depends on Support remote URLs for extension bundle zip installs #8724 so the published URL can be installed in one command. Without it, each install is "download the zip, then pass its path", which is the friction this is meant to remove.
Fork PR behavior needs a deliberate decision: fork PRs will not have storage credentials, so they should either be excluded (matching the CLI PR build posture) or handled explicitly. Contributors working in forks would continue to use azd x pack --bundle plus a shared URL.
Which PRs should trigger a build: the existing per-extension pipeline path filters are the natural scope.
Testing
Verification should cover that a PR touching an extension produces an installable bundle at the expected URL, that repeated pushes update the same URL and the same PR comment rather than creating new ones, that the published version is distinguishable from a release version, and that no publishing occurs for non-PR runs.
Summary
Partner teams developing first-party extensions regularly need to share a build from an unmerged branch with a customer or internal tester. Today that means either manually running
azd x pack --bundleand sending a.ziparound, or running the release pipeline against a feature branch, which has release-blocking side effects (#9408). This proposes building an extension bundle automatically for every PR that touches an extension, publishing it to Azure Storage, and posting install instructions as a PR comment.Motivation
The scenario that prompted this: a team needed to share RLE changes that had not yet merged with a 1P customer. The bundle
.zipflow works but was described as noticeably less convenient than an install command, and the release-pipeline workaround created a release and tag from a branch.Proposal
Mirror the existing CLI PR build pattern rather than inventing a new one.
eng/pipelines/templates/stages/publish.ymlalready has all the moving parts:Publish_For_PRdeployment job withenvironment: noneandisProduction: false, conditioned onBuild.ReasonbeingPullRequest.pr/$(PRNumber)).eng/pipelines/templates/steps/update-prcomment.ymlkeyed on an HTML comment tag, so the comment is updated in place instead of a new comment per push.Applied to extensions:
azd x pack --bundleand upload it toazd/extensions/pr/<PRNumber>/.Because the bundle contains every platform's artifacts, the comment is one command for all platforms, unlike the CLI PR comment which lists seven platform-specific URLs.
Why a bundle and not a per-PR registry.json
A per-PR
registry.jsonwould makeazd extension source addplusazd extension installwork and would enableazd extension upgrade, but it leaves durable state on the user's machine, and that state becomes actively harmful once the PR artifacts are pruned.Extension source resolution has no failover. In
pkg/extensions/manager.go, a source that fails to list returns immediately:So a single stale PR source whose blob has expired breaks
azd extension list --available,azd extension installfor unrelated extensions, andazd extension upgrade, until the user works out which source to remove. Anyone who tried a few PR builds would accumulate several of these. The documented "unreachable dev source blocks all operations" behavior is the same failure mode.Bundle installs leave no durable source: the transient source is removed after install and the extension is re-pointed at the reserved
bundlesource. That property is what makes PR-scoped artifacts safe to delete later.Version identity
PR builds should not be published as the plain manifest version, or
azd extension listcannot distinguish a PR build from a real release. Reuse the approach ineng/scripts/Set-ExtensionVersionVariable.ps1, which appends a semver-valid prerelease suffix for nightly builds.Known wrinkle worth documenting rather than solving here: appending a suffix to an already-prerelease base (
0.2.0-previewbecomes0.2.0-preview.pr.<n>.<buildid>) sorts above0.2.0-previewunder semver precedence, so a user on a PR build is not automatically superseded by the matching release. This is the same caveat already documented for nightly prerelease bases.Retention
PR artifacts should expire. An Azure Storage lifecycle rule on the
pr/prefix is preferable to bespoke pipeline cleanup: it cannot silently fail and it can cover the existing CLI PR builds underazd/standalone/pr/at the same time. With the bundle approach, expiry only invalidates an old link and cannot break a user's extension setup.This is distinct from #9177, which covers pruning entries from the nightly, dev, and prod registries.
Dependencies and open questions
azd x pack --bundleplus a shared URL.Testing
Verification should cover that a PR touching an extension produces an installable bundle at the expected URL, that repeated pushes update the same URL and the same PR comment rather than creating new ones, that the published version is distinguishable from a release version, and that no publishing occurs for non-PR runs.