Introducing Azure DevOps Marketplace tasks and actions: A Complete Rebuild for Speed, Stability, and Security
Introducing the Azdo marketplace project. Azure Pipelines tasks and GitHub Actions for publishing to the Azure DevOps marketplace.
The Azure DevOps Extension Tasks have an interesting heritage. What started as a private project written in PowerShell evolved into a critical piece of infrastructure for delivering extensions to the Azure DevOps. Shortly after the initial release f the PowerShell version, it was merged with the ALM Rangers project, adopted by Microsoft DevLabs, and became the de facto standard for organizations to automate extension publishing through CI/CD pipelines.
Over the last decade, I've been maintaining this project, watching it grow from a simple set of PowerShell scripts into an ever more complex collection of Typescript modules. During that time, thousands of extensions have been published using these tasks, touching millions of developers worldwide. The v5 version served the community well for years, but refactoring this beast was long overdue.
Growth Without Foundation
When we trace the footprint of the extension tasks, the numbers tell the story of accumulated technical debt:
The Original PowerShell Implementation: ~700 KB
- Simple, lean, purpose-built
After Migration to TypeScript: ~30 MB
- Better tooling support, stronger typing, but significantly larger
After Adding AzureRM Support & Visual Studio Extension Publisher and more tasks: ~300 MB
- Feature-complete, but bloated and complex
The real breaking point came with the introduction of signed pipeline requirements for SBOM (Software Bill of Materials) and security compliance. These mandates forced me into increasingly fragile workarounds:
- Complex hacks to manipulate manifests and VSIX files
- Brittle dependencies on tool versions and undocumented APIs
- Fragile post-processing steps that broke with every update
Meanwhile, the project had accumulated a critical weakness: inadequate test coverage. With such a complex system and so few tests, every change was a potential breaking change. I was hesitant to refactor, upgrade dependencies, or try new approaches.
The Decision: Time to Rebuild
After a decade of maintenance and learning what works and what doesn't, I made a decision in late 2025: rather than continue patching a brittle system, I would rebuild the entire project from first principles.
Over those ten years, I frequently wished to refactor the older codebase and managed to chip away at improvements here and there. But without comprehensive test coverage, each refactoring risked breaking something critical in production, used by thousands of organizations. The technical debt accumulated faster than it could be repaid.
The real game-changer came with GitHub Copilot's Coding Agent. Rather than me manually rewriting the logic, the agent could:
- Extract an extensive test suite from the existing v5 tasks, understanding the original behavior
- Build a new, architecturally superior implementation that passed all those tests, ensuring functionality remained intact
- Consolidate and simplify the codebase by identifying redundancies and streamlining design patterns
- Serve as a rubber ducky — challenging solution directions, suggesting alternatives, and forcing me to articulate requirements more clearly
This symbiotic relationship between human guidance and AI capability made the rebuild feasible. I could focus on architecture and design while the agent handled the bulk of implementation, constantly validating that nothing broke in the process.
The core principles for the new build were:
- Clean architecture - separate concerns, testable code
- Comprehensive test coverage - confidence in every change
- Reduced file size - back to a reasonable deployment footprint
- Modern dependencies - latest TypeScript, security patches, best practices
- Cross-platform support - work identically on Azure Pipelines AND GitHub Actions
- Enhanced security - eliminate reliance on Personal Access Tokens
- Long-standing bugs fixed - address a decade of user requests
The result? The numbers speak for themselves:
- 432 commits to get from v5 to v6
- 120 pull requests reviewed and merged
- 500+ tests covering core logic, integration paths, and end-to-end flows
- 20 MB bundle size (down from 300 MB)
- Coverage across Windows, macOS, and Linux in CI
And what's best of all, I managed to let the Copilot Coding Agent do most of the heavy lifting.
What's New in v6
Adds full support for GitHub Actions
So far these tasks have only been available to Azure Pipelines. But with GitHub growing in popularity, and my own interests shifting in that direction as well, it was time for a port to GitHub Actions.
The new architecture supports significant code sharing between the two platforms, but there are a few fundamental differences between the platforms. Most significant of all, the authentication options:
- Authenticate to Azure DevOps using GitHub Actions OIDC — New in v6
- Exclusively for GitHub Actions
- Exchange a GitHub OIDC token for Azure DevOps access
- Configure GitHub-to-Azure DevOps OIDC »
- Legacy Support
- PAT and Basic Auth remain available for backward compatibility through GitHub Actions Secrets.
With OIDC your CI/CD pipelines no longer store secrets in service connections or GitHub secrets. Instead, they use short-lived, federated tokens issued by your identity provider. This dramatically improves supply chain security.
Read more about securing your publishing workflows:
- Say Goodbye to Personal Access Tokens (PATs) - Jesse Houwing »
- Publish Azure DevOps Extensions Using Workload Identity (OIDC) - Jesse Houwing »
Unified Platform Support
V6 can be used on both Azure Pipelines and GitHub Actions, with identical behavior:
# Azure Pipelines
- task: azdo-marketplace@6
inputs:
operation: publish
publisherId: mycompany
extensionId: my-extension
# GitHub Actions
- uses: jessehouwing/azdo-marketplace@v6
with:
operation: publish
publisher-id: mycompany
extension-id: my-extensionThis unified core means extension developers can now migrate effortlessly between platforms, or even use both simultaneously for redundancy.
New Features
Beyond the rebuild, v6 introduces features requested over the years:
- Wait for Installation - add a gate in your pipeline that waits for the extension to install on target organizations
- Unshare Extension - remove an extension from shared organizations
- Unpublish Extension - remove an extension from the public marketplace completely
- Read and write VSIX Metadata - extract and update metadata directly from a VSIX file without unpacking the whole file
- Aligned Inputs - consistent input names and behavior across all tasks
- Unified Task Design - all 10 operations (
package,publish,install,share,unshare,unpublish,show,query-version,wait-for-installation,wait-for-validation) are one task with anoperationinput
Comprehensive Testing and CI
The new project features an extensive CI/CD workflow that:
- ✅ Runs 500+ unit and integration tests
- ✅ Tests on Windows and Linux runners
- ✅ Validates every authentication method
- ✅ Exercises all CLI code paths
- ✅ Auto-publishes the task to the marketplace for validation
- ✅ Tests both Azure Pipelines and GitHub Actions adapters
- ✅ Runs validation workflows on Azure Pipelines and GitHub Actions
This comprehensive validation means breaking changes are caught before they reach users.
Getting Started
New to Extension Publishing?
If you're just starting out, here's a minimal CI/CD setup using v6:
- Create service connection in Azure DevOps:
- Use
AzureRMfor best security - Or
Personal Access Tokenfor quick start, you can move toAzureRMlater
- Use
- Set up your Azure Pipelines YAML:
trigger:
- main
stages:
- stage: Package
jobs:
- job: Build and publish
steps:
- task: azdo-marketplace@6
inputs:
operation: package
manifestFile: vss-extension.json
outputPath: $(Build.ArtifactStagingDirectory)
- task: azdo-marketplace@6
inputs:
operation: publish
vsixFile: $(Build.ArtifactStagingDirectory)/*.vsix
connectionType: azureRm
connectionNameAzureRm: $(serviceConnection)
For GitHub Actions, the structure is similar but uses the action syntax.
Migrating from v5?
v5 focused on a task-per-operation model. v6 unifies everything into one operation-routed task. The migration is straightforward:
v5:
- task: PackageExtension@5
inputs:
manifestFile: vss-extension.jsonv6:
- task: azdo-marketplace@6
inputs:
operation: package
manifestFile: vss-extension.jsonKey changes:
- Replace individual tasks with
azdo-marketplace@6 - Use the
operationinput to select the command - Adjust input names to match v6 schema
- Update authentication to use
connectionTypeand service connections
📖 Full v5 to v6 Migration Guide »
Migrating to GitHub Actions?
Moving from Azure Pipelines to GitHub Actions? v6 makes this transition smooth:
- Switch to GitHub Actions syntax (same operations available)
- Configure OIDC federation for authentication without having to manage tokens
- Adjust input names (kebab-case instead of camelCase)
- Update trigger conditions (GitHub Actions workflow triggers differ from Azure Pipelines)
The business logic remains identical across platforms, so your testing, validation, and publishing flows work exactly the same.
📖 Full Azure Pipelines to GitHub Actions Migration Guide »
Supply Chain Security: The Full Picture
V6 strengthens the security model introduced in v5 by expanding federated identity options across platforms and reducing reliance on long-lived credentials.
Why Workload Identity Matters
PATs are problematic because:
- They're typically long-lived tokens stored in CI/CD systems
- If exposed, they grant broad permissions to your entire Azure DevOps organization
- They're difficult to rotate and audit
- They provide no time-based or scope-based granularity
Workload Identity Federation solves this:
- Issues short-lived tokens (valid for 1 hour)
- Uses cryptographic proof of identity rather than shared secrets
- Enables role-based access control (who, what, where)
- Provides full audit trail through your identity provider
- Supports automatic token rotation
Deploying v6 Safely
How to set up federated identity for maximum security:
For GitHub Actions → Azure DevOps:
- Create an Azure App Registration representing your GitHub Actions workflow
- Configure OIDC federation to accept tokens from your GitHub org/repo
- Grant the minimal necessary permissions to that app
- GitHub Actions runner exchanges its OIDC token for Azure DevOps access
For Azure Pipelines → Azure DevOps (same org):
- Use Azure Managed Identity or service principal
- The tasks automatically fetch the token through the configured service connection
- No secrets in the pipeline configuration
Both approaches eliminate the need for any stored secrets.
Community-Driven Development
This v6 rebuild wouldn't have been possible without AI-assisted development. But AI is a tool; the project's direction comes from the community:
- Thousands of organizations depend on these tasks monthly
- Years of user feedback shaped which bugs to prioritize
- Community issues highlighted areas needing improvement
V6 is also built with the maintainability of contributions in mind:
- Clean, testable architecture makes adding features straightforward
- Extensive test coverage prevents regressions
- Platform abstraction means changes help users on both Azure Pipelines AND GitHub Actions
- Comprehensive documentation eases onboarding for new contributors
How You Can Help
I'm committed to making v6 the best version yet. Here's how you can contribute:
- Test on your own extensions: Deploy v6 to your publishing pipelines and share feedback
- Report issues: Use our GitHub issues tracker for bugs or feature requests
- Share successes: Let us know your deployment stories and use cases
- Contribute improvements: Check out our Contributing Guide
Support the Project: While GitHub Copilot did write 95% of the code, this rebuild still required significant time to guide the agent, shape architectural decisions, review implementations, and refine the final solution. If you find v6 valuable, consider supporting the maintenance and future development through GitHub Sponsors. Every contribution—whether financial or through testing and feedback—helps ensure v6 and the broader ecosystem of tools continue to improve.
Ecosystem Projects
The Azdo-Marketplace project is part of a larger ecosystem of tools for GitHub Actions and Azure Pipelines:
- azure-pipelines-dependency-submissions - automatically report Azure Pipelines dependencies to GitHub's dependency graph for supply chain visibility
- github-actions-dependency-submissions - automatically report dependencies to GitHub's dependency graph for supply chain visibility
- github-actions-semver-checker - verify that versioning follows semantic versioning rules and marketplace publishing steps are correct
- github-actions-example-checker - ensure all examples and documentation use correct input names and data types
These projects, combined with the Azdo Markeplace, create a complete, modern publishing toolkit.
Path Forward
This release will not be the last one; it is the blueprint for what comes next.
I maintains several Azure DevOps extensions, and my CI/CD pipelines will now gradually migrate over from Azure Pipelines to GitHub Actions. Wherever it makes sense, those projects will adopt the same rigorous testing approach proven in this v6 rebuild, including broader automation coverage and stronger validation gates.
You can find all my Azure DevOps projects here:
You can also find my GitHub Marketplace projects here:

While most of my current investment is in GitHub, these other projects will not be abandoned. They will continue to be maintained and improved. The strategic focus, however, is clear: help make the GitHub Actions platform an even better place to build, test, secure, and ship software.
Thank You
This project represents thousands of hours of collective work over 10 years. It's been maintained not out of obligation, but because it genuinely helps the community of extension developers publish safely and reliably.
This new release is incorporates many lessons learned and serves as a fresh start. It's built for the next chapter of Azure DevOps extension development.
Ready to get started?