Skip to content

Conversation

@MicroTuld
Copy link
Contributor

@MicroTuld MicroTuld commented Dec 16, 2025

Context

This PR includes a new Major version of the UniversalPackages task. There are many modifications (mostly reductions) to now obsolete inputs, plus implementation of the adoServiceConnection input. This will allow build identities and WIF to be used for downloading and publishing of Universal Packages (UPack) to and from Azure Artifacts feeds, without the use of PATs.

AB#2327595

Task Name

UniversalPackagesV1


Description

  • Rework the entire UniversalPackages task for the new version.
  • Include L0 tests and testing framework to prevent regression.

Files:
Task:

  • universalMain.ts - launching point for the task. Triggers common validation, setup, and ArtifactTool download common between download and publish.
  • universalDownload.ts - logic distinct to the download command.
  • universalPublish.ts - logic distinct to the publish command, including provenance.
  • universalPackageHelpers.ts - functions and tools.
  • UniversalPackageContext.ts - stores inputs and other properties as a state object for passing between functions.

Tests:

  • L0.ts - suite of tests
  • testRunner.ts - used to spawn node processes for the tests. Collects env variables as test inputs.
  • TestConstant.ts - values for the tests to eliminate "magic strings"
  • TestHelpers.ts - assertion and setup functions
  • UniversalMockHelper.ts - mocks for all external operations, plus a MockConfig object for properties.
  • UniversalMockTestRunner - extends MockTestRunner to extract task output for validation.

Risk Assessment (Low / Medium / High)

Medium. There is no backward compatibility, and it is a new task. However, it does not break existing usage of the V0 task.


Change Behind Feature Flag (Yes / No)

No. It's a new task.


Tech Design / Approach

  • Design has been written and reviewed. Yes
  • Any architectural decisions, trade-offs, and alternatives are captured. Yes

Documentation Changes Required (Yes/No)

Yes -- once the task reaches public availability docs will need to be updated to include the new major version.


Unit Tests Added or Updated (Yes / No)

Yes


Additional Testing Performed

Extensive end-to-end testing in pipelines, including both download and publish commands, varied feed scopes, windows/macOS/linux environments, error validation, etc.


Logging Added/Updated (Yes/No)

Yes


Telemetry Added/Updated (Yes/No)

No telemetry beyond logging and that which is included in the framework.


Rollback Scenario and Process (Yes/No)

N/A - it's a new task.


Dependency Impact Assessed and Regression Tested (Yes/No)

Yes


Checklist

  • Related issue linked (if applicable)
  • Task version was bumped — see versioning guide
  • Verified the task behaves as expected

@MicroTuld MicroTuld enabled auto-merge (squash) December 16, 2025 21:20
@MicroTuld MicroTuld disabled auto-merge December 16, 2025 21:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces UniversalPackagesV1, a new major version of the Universal Packages task that adds support for Workload Identity Federation (WIF) authentication and Azure DevOps service connections. This enables downloading and publishing Universal Packages to/from Azure Artifacts feeds using build identities and WIF without requiring Personal Access Tokens (PATs).

Key Changes:

  • Added new adoServiceConnection input for WIF-based authentication with service connections
  • Implemented provenance session support for publish operations when using service connections
  • Restructured task code with clearer separation between download, publish, and helper modules
  • Added comprehensive L0 test suite with mocking infrastructure

Reviewed changes

Copilot reviewed 19 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
make-options.json Registers UniversalPackagesV1 in build system task lists
task.json / task.loc.json Task definition with new inputs for service connection and organization
universalMain.ts Main entry point with validation and command routing logic
universalDownload.ts Download command implementation using ArtifactTool
universalPublish.ts Publish command with provenance session support
universalPackageHelpers.ts Authentication, feed validation, and artifact tool management
UniversalPackageContext.ts Context object for passing state between functions
Tests/*.ts Comprehensive L0 test suite with mock infrastructure
Strings/resources.resjson Localized strings for messages and help text
package.json Task dependencies and build scripts
CODEOWNERS Ownership assignment to azure-artifacts-packages team
Files not reviewed (1)
  • Tasks/UniversalPackagesV1/package-lock.json: Language not supported

"Error_UnexpectedErrorArtifactToolDownload": "An unexpected error occurred while trying to download the package. Exit code(%s) and error(%s)",
"Error_UnexpectedErrorArtifactToolPublish": "An unexpected error occurred while trying to push the package. Exit code(%s) and error(%s)",
"Error_UniversalPackagesNotSupportedOnPrem": "Universal Packages are not supported in Azure DevOps Server.",
"Success_PackagesDownloaded": "Package were downloaded successfully",
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "Package were downloaded successfully" contains a grammatical error. It should be "Packages were downloaded successfully" (plural form).

Suggested change
"Success_PackagesDownloaded": "Package were downloaded successfully",
"Success_PackagesDownloaded": "Packages were downloaded successfully",

Copilot uses AI. Check for mistakes.
"loc.messages.Error_UnexpectedErrorArtifactToolDownload": "An unexpected error occurred while trying to download the package. Exit code(%s) and error(%s)",
"loc.messages.Error_UnexpectedErrorArtifactToolPublish": "An unexpected error occurred while trying to push the package. Exit code(%s) and error(%s)",
"loc.messages.Error_UniversalPackagesNotSupportedOnPrem": "Universal Packages are not supported in Azure DevOps Server.",
"loc.messages.Success_PackagesDownloaded": "Package were downloaded successfully",
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "Package were downloaded successfully" contains a grammatical error. It should be "Packages were downloaded successfully" (plural form).

Suggested change
"loc.messages.Success_PackagesDownloaded": "Package were downloaded successfully",
"loc.messages.Success_PackagesDownloaded": "Packages were downloaded successfully",

Copilot uses AI. Check for mistakes.

function parseFeedInput(feed: string): { feedName: string; projectName: string | null } {
let feedName: string;
let projectName: string = null;
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable projectName is initialized as a string but should be initialized to null (not the string "null") to match the type annotation. This could cause issues when checking if projectName is truthy.

Suggested change
let projectName: string = null;
let projectName: string | null = null;

Copilot uses AI. Check for mistakes.
"type": "string",
"label": "Package name",
"required": true,
"helpMarkDown": "The name of the Universal Package. Package names must be lower case and can only use letters, numbers, and dashes(-)."
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The help text contains a typo: "dashes(-)" should include a space before the parenthesis for better readability: "dashes (-)". This appears in both the regular and localized versions.

Suggested change
"helpMarkDown": "The name of the Universal Package. Package names must be lower case and can only use letters, numbers, and dashes(-)."
"helpMarkDown": "The name of the Universal Package. Package names must be lower case and can only use letters, numbers, and dashes (-)."

Copilot uses AI. Check for mistakes.
"loc.input.label.feed": "Feed",
"loc.input.help.feed": "The feed name. For project-scoped feeds, use 'project/feed' format.",
"loc.input.label.packageName": "Package name",
"loc.input.help.packageName": "The name of the Universal Package. Package names must be lower case and can only use letters, numbers, and dashes(-).",
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The help text contains a typo: "dashes(-)" should include a space before the parenthesis for better readability: "dashes (-)". This appears in both the regular and localized versions.

Suggested change
"loc.input.help.packageName": "The name of the Universal Package. Package names must be lower case and can only use letters, numbers, and dashes(-).",
"loc.input.help.packageName": "The name of the Universal Package. Package names must be lower case and can only use letters, numbers, and dashes (-).",

Copilot uses AI. Check for mistakes.
{
"id": "e0b79640-8625-11e8-91be-db2878ff888a",
"name": "UniversalPackages",
"friendlyName": "Universal packages",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be Universal Packages


"execution": {
"Node10": {
"target": "universalMain.js",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to support all these node versions ? are there any active node migrations we can get ahead of ?

@@ -0,0 +1,33 @@
{
"name": "universalpackages",
"version": "1.267.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this version used at all in this repo? should it be a simple 1.0.0 ?

if (context.adoServiceConnection) {
tl.debug(tl.loc('Debug_UsingWifAuth', context.adoServiceConnection));
try {
accessToken = await getFederatedWorkloadIdentityCredentials(context.adoServiceConnection);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we are not passing the tenant id to the getFederatedWorkloadIdentityCredentials. This will be needed for cross tenant feeds.

Can we use the getfeedTentantId if available?


tl.debug(tl.loc('Debug_UsingServiceUri', serviceUri));

toolRunnerOptions.env.UNIVERSAL_AUTH_TOKEN = accessToken;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this variable is set in the pipeline from a previous step or process are we overwritting? Do we want to enable this env being set by another process ?

}

// This will throw if the feed doesn't exist or token doesn't have access
const data = await webApi.vsoClient.getVersioningData(ApiVersion, PackagingAreaName, PackageAreaId, routeValues);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this validate feed access just testing read ? Because it seems like this could pass but then fail for publish if they do not have write access. Do we care? In this case does it make sense to do this check still ?

"packageName": tl.getInput("packageName"),
"adoServiceConnection": tl.getInput("adoServiceConnection"),
"System.TeamFoundationCollectionUri": tl.getVariable("System.TeamFoundationCollectionUri"),
"verbosity": tl.getInput("verbosity"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a question about versbosity - can we determine if the system.debug predifined variable is set and set the verbosity to debug if true?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is more for the context than just the telemetery

"command": tl.getInput("command"),
"organization": tl.getInput("organization"),
"feed": tl.getInput("feed"),
"packageName": tl.getInput("packageName"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would package version be helpful here too ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants