@@ -20,7 +20,12 @@ parameters:
2020 - preview
2121
2222 - name : publishPackage
23- displayName : 🚀 Publish to npm
23+ displayName : 🚀 Publish npm
24+ type : boolean
25+ default : false
26+
27+ - name : publishToConsumptionFeed
28+ displayName : 📡 Publish to msft_consumption feed
2429 type : boolean
2530 default : false
2631
@@ -56,6 +61,18 @@ variables:
5661 value : next
5762 ${{ else }} :
5863 value : latest
64+ - name : AzureArtifactsFeedUrl
65+ value : ' https://pkgs.dev.azure.com/azure-public/vside/_packaging/python-environments/npm/registry/'
66+ # Same URL without the https:// prefix (used in .npmrc auth lines)
67+ - name : AzureArtifactsFeedUrlNoProtocol
68+ value : ' pkgs.dev.azure.com/azure-public/vside/_packaging/python-environments/npm/registry/'
69+ # Managed Identity service connection for Azure Artifacts auth (shared with Pylance)
70+ - name : AzureServiceConnection
71+ value : ' PylanceSecureVsIdePublishWithManagedIdentity'
72+ - name : ConsumptionFeedUrl
73+ value : ' https://pkgs.dev.azure.com/azure-public/vside/_packaging/msft_consumption/npm/registry/'
74+ - name : ConsumptionFeedUrlNoProtocol
75+ value : ' pkgs.dev.azure.com/azure-public/vside/_packaging/msft_consumption/npm/registry/'
5976
6077extends :
6178 template : azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
@@ -97,30 +114,111 @@ extends:
97114 targetFolder : $(Build.ArtifactStagingDirectory)
98115
99116 - stage : Publish
100- displayName : Publish to npm
117+ displayName : Publish to Azure Artifacts
101118 dependsOn : Build
102119 condition : and(succeeded(), eq('${{ parameters.publishPackage }}', 'true'))
103120 jobs :
104121 - job : PublishPackage
105122 displayName : Publish $(PackageName)
106- steps :
107- - task : DownloadPipelineArtifact@2
108- displayName : Download build artifact
109- inputs :
123+ templateContext :
124+ type : releaseJob
125+ isProduction : true
126+ inputs :
127+ - input : pipelineArtifact
110128 artifactName : npm-package
111- targetPath : $(Build.ArtifactStagingDirectory)/npm-package
129+ targetPath : $(Pipeline.Workspace)/npm-package
130+ steps :
131+ - checkout : none
112132
113133 - task : NodeTool@0
114134 inputs :
115135 versionSpec : ' 22.21.1'
116136 displayName : Select Node version
117137
118- - bash : echo '//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}' > .npmrc
119- workingDirectory : $(Build.SourcesDirectory)/pythonEnvironmentsApi
120- displayName : Configure npm auth
138+ # Acquire a short-lived AAD token via Managed Identity (no stored secrets)
139+ # SEE https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-security-configuration/configuration-guides/pat-burndown-guidance
140+ - task : AzureCLI@2
141+ displayName : Acquire AAD token via Managed Identity
142+ inputs :
143+ azureSubscription : ' $(AzureServiceConnection)'
144+ scriptType : ' pscore'
145+ scriptLocation : ' inlineScript'
146+ inlineScript : |
147+ $token = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv
148+ Write-Host "##vso[task.setvariable variable=AzdoToken;issecret=true]$token"
149+
150+ - powershell : |
151+ @"
152+ registry=$(AzureArtifactsFeedUrl)
153+ always-auth=true
154+ "@ | Out-File -FilePath .npmrc
155+
156+ @"
157+ ; begin auth token
158+ //$(AzureArtifactsFeedUrlNoProtocol):username=VssSessionToken
159+ //$(AzureArtifactsFeedUrlNoProtocol):_authToken=$env:AZDO_TOKEN
160+ //$(AzureArtifactsFeedUrlNoProtocol):email=not-used@example.com
161+ ; end auth token
162+ "@ | Out-File -FilePath $HOME/.npmrc
163+ env:
164+ AZDO_TOKEN: $(AzdoToken)
165+ displayName: Create .npmrc files
166+
167+ - powershell : |
168+ $tgz = Get-ChildItem "$(Pipeline.Workspace)/npm-package/*.tgz" | Select-Object -First 1
169+ if (-not $tgz) {
170+ Write-Error "No .tgz file found in $(Pipeline.Workspace)/npm-package/"
171+ exit 1
172+ }
173+ Write-Host "Publishing: $($tgz.FullName)"
174+ if ("$(npmTag)" -eq "next") {
175+ npm publish $tgz.FullName --registry $(AzureArtifactsFeedUrl) --tag next --ignore-scripts
176+ } else {
177+ npm publish $tgz.FullName --registry $(AzureArtifactsFeedUrl) --ignore-scripts
178+ }
179+ displayName: npm publish (${{ parameters.quality }})
180+
181+ - stage : PublishConsumption
182+ displayName : Publish package to msft_consumption feed
183+ dependsOn : Publish
184+ condition : and(not(failed()), eq('${{ parameters.publishToConsumptionFeed }}', 'true'))
185+ jobs :
186+ - job : PullToConsumption
187+ displayName : Pull $(PackageName) to msft_consumption
188+ steps :
189+ - checkout : none
190+
191+ - task : NodeTool@0
192+ inputs :
193+ versionSpec : ' 22.21.1'
194+ displayName : Select Node version
121195
122- - bash : npm publish $(Build.ArtifactStagingDirectory)/npm-package/*.tgz --tag $(npmTag) --access public --ignore-scripts
123- displayName : Publish to npm (${{ parameters.quality }})
124- workingDirectory : $(Build.SourcesDirectory)/pythonEnvironmentsApi
196+ - task : AzureCLI@2
197+ displayName : Acquire AAD token via Managed Identity
198+ inputs :
199+ azureSubscription : ' $(AzureServiceConnection)'
200+ scriptType : ' pscore'
201+ scriptLocation : ' inlineScript'
202+ inlineScript : |
203+ $token = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv
204+ Write-Host "##vso[task.setvariable variable=AzdoToken;issecret=true]$token"
205+
206+ - powershell : |
207+ @"
208+ registry=$(ConsumptionFeedUrl)
209+ always-auth=true
210+ "@ | Out-File -FilePath .npmrc
211+
212+ @"
213+ ; begin auth token
214+ //$(ConsumptionFeedUrlNoProtocol):username=VssSessionToken
215+ //$(ConsumptionFeedUrlNoProtocol):_authToken=$env:AZDO_TOKEN
216+ //$(ConsumptionFeedUrlNoProtocol):email=not-used@example.com
217+ ; end auth token
218+ "@ | Out-File -FilePath $HOME/.npmrc
125219 env:
126- NODE_AUTH_TOKEN : $(NpmAuthToken)
220+ AZDO_TOKEN: $(AzdoToken)
221+ displayName: Create .npmrc files
222+
223+ - script : npm i -g $(PackageName)@$(npmTag) --registry $(ConsumptionFeedUrl)
224+ displayName : Pull to msft_consumption
0 commit comments