Skip to content

Commit b393571

Browse files
chiaramooneyCopilotCopilotnmetulevgithub-actions[bot]
authored
Upstream Pipeline Changes for VSCE (#519)
## Description Upstream pipeline changes for VSCE. Formatting fixes, use service connection instead of PAT, adds ESRP signing, etc. ## Type of Change <!-- Keep the applicable line(s), delete the rest --> - 🔧 Config/build ## AI Description <!-- ai-description-start --> This pull request updates the upstream pipeline for VSCE, implementing various changes such as formatting fixes, the use of service connections instead of PATs, and the addition of ESRP signing. It also introduces new parameters for the pipeline, specifically `DoEsrp` for signing VSIX packages. New usage example: ```yaml parameters: - name: DoEsrp displayName: Sign the VSIX package (DoEsrp) type: boolean default: true ``` <!-- ai-description-end --> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent c81824d commit b393571

6 files changed

Lines changed: 3970 additions & 380 deletions

File tree

.pipelines/release-vsc.yml

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
trigger:
2+
batch: true
23
branches:
34
include:
45
- vsc-rel/v*
@@ -19,6 +20,10 @@ parameters:
1920
- name: SkipPublish
2021
displayName: Skip publishing to VS Code Marketplace
2122
type: boolean
23+
default: false
24+
- name: DoEsrp
25+
displayName: Sign the VSIX package (DoEsrp)
26+
type: boolean
2227
default: true
2328

2429
extends:
@@ -31,6 +36,8 @@ extends:
3136
os: windows
3237
stages:
3338
- stage: Build
39+
variables:
40+
- group: signingIdentity
3441
jobs:
3542
- job: Build
3643
pool:
@@ -44,58 +51,62 @@ extends:
4451
displayName: Setup Node.js 24
4552
inputs:
4653
version: '24.x'
54+
- ${{ if eq(parameters.DoEsrp, 'true') }}:
55+
- task: UseDotNet@2
56+
displayName: Setup .NET 8.0 (For ESRP Task)
57+
inputs:
58+
packageType: runtime
59+
version: 8.0.x
4760
- task: PowerShell@2
4861
displayName: Download public CLI release for VS Code extension
62+
env:
63+
GH_TOKEN: $(GITHUB_TOKEN)
4964
inputs:
5065
pwsh: true
66+
errorActionPreference: 'stop'
5167
targetType: 'inline'
5268
script: |
5369
$cliReleaseTag = "${{ parameters.CliReleaseTag }}"
5470
$repo = "microsoft/winappcli"
5571
5672
if ([string]::IsNullOrWhiteSpace($cliReleaseTag)) {
5773
Write-Host "No CLI release tag specified, finding latest stable release..."
58-
$releases = Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/releases" -Headers @{ "User-Agent" = "AzurePipelines" }
59-
$stableRelease = $releases | Where-Object { -not $_.prerelease -and -not $_.draft } | Select-Object -First 1
74+
$releases = gh release list --repo $repo --limit 10 --json tagName,isPrerelease,isDraft | ConvertFrom-Json
75+
$stableRelease = $releases | Where-Object { -not $_.isPrerelease -and -not $_.isDraft } | Select-Object -First 1
6076
if (-not $stableRelease) {
6177
Write-Error "No stable release found for $repo"
6278
exit 1
6379
}
64-
$cliReleaseTag = $stableRelease.tag_name
80+
$cliReleaseTag = $stableRelease.tagName
6581
Write-Host "Found latest stable release: $cliReleaseTag"
6682
} else {
6783
Write-Host "Using specified CLI release tag: $cliReleaseTag"
6884
}
6985
7086
Write-Host "##vso[task.setvariable variable=CliReleaseTag]$cliReleaseTag"
7187
72-
# Download x64 and arm64 CLI zips
73-
$downloadBase = "https://github.com/$repo/releases/download/$cliReleaseTag"
88+
# Download x64 and arm64 CLI zips using gh CLI
7489
$cliDir = "$(System.DefaultWorkingDirectory)/artifacts/public-cli"
7590
7691
New-Item -ItemType Directory -Path "$cliDir/win-x64" -Force | Out-Null
7792
New-Item -ItemType Directory -Path "$cliDir/win-arm64" -Force | Out-Null
7893
79-
$x64Url = "$downloadBase/winappcli-x64.zip"
80-
$arm64Url = "$downloadBase/winappcli-arm64.zip"
81-
82-
Write-Host "Downloading x64 CLI from: $x64Url"
83-
Invoke-WebRequest -Uri $x64Url -OutFile "$cliDir/x64.zip"
84-
if ($LASTEXITCODE -ne 0 -or -not (Test-Path "$cliDir/x64.zip")) {
85-
Write-Error "Failed to download x64 CLI from $x64Url"
94+
Write-Host "Downloading CLI binaries from release $cliReleaseTag..."
95+
gh release download $cliReleaseTag --repo $repo --pattern "winappcli-x64.zip" --dir $cliDir
96+
if ($LASTEXITCODE -ne 0) {
97+
Write-Error "Failed to download winappcli-x64.zip from release $cliReleaseTag"
8698
exit 1
8799
}
88100
89-
Write-Host "Downloading arm64 CLI from: $arm64Url"
90-
Invoke-WebRequest -Uri $arm64Url -OutFile "$cliDir/arm64.zip"
91-
if ($LASTEXITCODE -ne 0 -or -not (Test-Path "$cliDir/arm64.zip")) {
92-
Write-Error "Failed to download arm64 CLI from $arm64Url"
101+
gh release download $cliReleaseTag --repo $repo --pattern "winappcli-arm64.zip" --dir $cliDir
102+
if ($LASTEXITCODE -ne 0) {
103+
Write-Error "Failed to download winappcli-arm64.zip from release $cliReleaseTag"
93104
exit 1
94105
}
95106
96107
# Extract
97-
Expand-Archive -Path "$cliDir/x64.zip" -DestinationPath "$cliDir/win-x64" -Force
98-
Expand-Archive -Path "$cliDir/arm64.zip" -DestinationPath "$cliDir/win-arm64" -Force
108+
Expand-Archive -Path "$cliDir/winappcli-x64.zip" -DestinationPath "$cliDir/win-x64" -Force
109+
Expand-Archive -Path "$cliDir/winappcli-arm64.zip" -DestinationPath "$cliDir/win-arm64" -Force
99110
100111
# Validate
101112
if (-not (Test-Path "$cliDir/win-x64/winapp.exe")) {
@@ -108,12 +119,58 @@ extends:
108119
}
109120
110121
Write-Host "CLI binaries ($cliReleaseTag) downloaded and validated successfully"
122+
- task: PowerShell@2
123+
displayName: Create temporary .npmrc for Build
124+
inputs:
125+
targetType: inline
126+
pwsh: true
127+
script: |
128+
$npmrcContent = "registry=https://pkgs.dev.azure.com/microsoft/pde-oss/_packaging/winapp-npm-feed/npm/registry/`nalways-auth=true"
129+
Set-Content -Path "$(System.DefaultWorkingDirectory)/src/winapp-VSC/.npmrc" -Value $npmrcContent
130+
Write-Host "Created .npmrc for Azure Artifacts feed in winapp-VSC directory"
131+
- task: npmAuthenticate@0
132+
displayName: Authenticate with Azure Artifacts feed
133+
inputs:
134+
workingFile: '$(System.DefaultWorkingDirectory)/src/winapp-VSC/.npmrc'
111135
- task: PowerShell@2
112136
displayName: Package VS Code extension with public CLI
113137
inputs:
114138
pwsh: true
115139
filePath: $(System.DefaultWorkingDirectory)\scripts\package-vsc.ps1
116140
arguments: "-Stable -CliBinariesPath '$(System.DefaultWorkingDirectory)/artifacts/public-cli'"
141+
- ${{ if eq(parameters.DoEsrp, 'true') }}:
142+
- task: EsrpCodeSigning@5
143+
displayName: Code Sign ESRP - VSIX Package
144+
inputs:
145+
ConnectedServiceName: $(SigningServiceName)
146+
AppRegistrationClientId: $(SigningAppId)
147+
AppRegistrationTenantId: $(SigningTenantId)
148+
AuthAKVName: $(SigningAKVName)
149+
AuthCertName: $(SigningAuthCertName)
150+
AuthSignCertName: $(SigningSignCertName)
151+
FolderPath: '$(System.DefaultWorkingDirectory)/artifacts/'
152+
Pattern: '*.vsix'
153+
UseMinimatch: true
154+
signConfigType: inlineSignParams
155+
inlineOperation: |
156+
[
157+
{
158+
"KeyCode": "CP-401405",
159+
"OperationCode": "OpcSign",
160+
"Parameters": {
161+
"FileDigest": "/fd SHA256"
162+
},
163+
"ToolName": "sign",
164+
"ToolVersion": "1.0"
165+
},
166+
{
167+
"KeyCode": "CP-401405",
168+
"OperationCode": "OpcVerify",
169+
"Parameters": {},
170+
"ToolName": "sign",
171+
"ToolVersion": "1.0"
172+
}
173+
]
117174
- task: CopyFiles@2
118175
displayName: Copy Artifacts - VS Code Extension
119176
inputs:
@@ -131,7 +188,7 @@ extends:
131188
dependsOn: Build
132189
condition: and(succeeded(), eq('${{ parameters.SkipPublish }}', 'false'))
133190
variables:
134-
- group: vsceMarketplaceIdentity
191+
- group: signingIdentity
135192
jobs:
136193
- job: publish_vsc_extension
137194
pool:
@@ -164,36 +221,21 @@ extends:
164221
displayName: Authenticate with Azure Artifacts feed
165222
inputs:
166223
workingFile: '.npmrc'
167-
- task: PowerShell@2
168-
displayName: "Publish to VS Code Marketplace"
169-
env:
170-
VSCE_PAT: $(VSCE_PAT)
224+
- task: AzureCLI@2
225+
displayName: Publish to VS Code Marketplace
171226
inputs:
172-
targetType: 'inline'
173-
errorActionPreference: 'stop'
174-
script: |
175-
Write-Host "Installing @vscode/vsce..."
176-
npm install @vscode/vsce
177-
if ($LASTEXITCODE -ne 0) {
178-
Write-Error "Failed to install @vscode/vsce"
179-
exit 1
180-
}
181-
182-
$vsix = Get-ChildItem "$(Pipeline.Workspace)/vscode-extension/" -Filter "*.vsix" | Select-Object -First 1
183-
if (-not $vsix) {
184-
Write-Error "No VSIX file found in vscode-extension artifact"
185-
exit 1
186-
}
187-
188-
$sizeMB = [math]::Round($vsix.Length / 1MB, 2)
189-
Write-Host "Publishing $($vsix.Name) ($sizeMB MB) to VS Code Marketplace..."
190-
191-
npx vsce publish --packagePath $vsix.FullName
192-
if ($LASTEXITCODE -ne 0) {
193-
Write-Error "Failed to publish to VS Code Marketplace"
227+
azureSubscription: $(SigningServiceName)
228+
scriptType: bash
229+
scriptLocation: inlineScript
230+
inlineScript: |
231+
npm install -g @vscode/vsce@3
232+
233+
VSIX=$(find "$(Pipeline.Workspace)/vscode-extension/" -name "*.vsix" | head -1)
234+
if [ -z "$VSIX" ]; then
235+
echo "##[error]No VSIX file found in vscode-extension artifact"
194236
exit 1
195-
}
196-
197-
Write-Host "Successfully published to VS Code Marketplace!"
237+
fi
198238
239+
echo "Publishing $VSIX to VS Code Marketplace..."
240+
vsce publish --packagePath "$VSIX" --azure-credential
199241

scripts/package-vsc.ps1

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,12 @@ try
185185
$CliVersion = "unknown"
186186
if (Test-Path $CliExe) {
187187
try {
188-
$RawCliVersion = & $CliExe --version 2>$null
189-
if (-not [string]::IsNullOrWhiteSpace($RawCliVersion)) {
188+
$RawOutput = & $CliExe --version 2>$null
189+
# Output may contain ASCII banner art; find the line matching semver pattern
190+
$VersionLine = $RawOutput | Where-Object { $_ -match '^\d+\.\d+\.\d+' } | Select-Object -First 1
191+
if (-not [string]::IsNullOrWhiteSpace($VersionLine)) {
190192
# Strip git hash suffix (e.g., "1.0.0+abc123" -> "1.0.0")
191-
$CliVersion = ($RawCliVersion.Trim() -split '\+')[0]
193+
$CliVersion = ($VersionLine.Trim() -split '\+')[0]
192194
}
193195
} catch {
194196
Write-Warning "Could not determine CLI version from binary"
@@ -212,29 +214,12 @@ try
212214
$PackageJson.version = $Version
213215
$PackageJson | ConvertTo-Json -Depth 100 | Set-Content $PackageJsonPath
214216

215-
# Check if vsce is available, install if needed
216-
$VsceCmd = Get-Command vsce -ErrorAction SilentlyContinue
217-
if (-not $VsceCmd) {
218-
Write-Host "[VSC] Installing @vscode/vsce..." -ForegroundColor Blue
219-
npm install -g @vscode/vsce
220-
if ($LASTEXITCODE -ne 0) {
221-
Write-Error "Failed to install @vscode/vsce"
222-
# Restore package.json and README.md before exiting
223-
Move-Item "$PackageJsonPath.backup" $PackageJsonPath -Force
224-
if (Test-Path "$ReadmePath.backup") {
225-
Move-Item "$ReadmePath.backup" $ReadmePath -Force
226-
}
227-
Pop-Location
228-
exit 1
229-
}
230-
}
231-
232-
# Package the VSIX
217+
# Package the VSIX (vsce installed via npm ci from devDependencies)
233218
Write-Host "[PACK] Creating VSIX package..." -ForegroundColor Blue
234219

235220
$RelativeOutputPath = [System.IO.Path]::GetRelativePath($VscProjectPath, $OutputPath)
236221

237-
vsce package --no-dependencies -o "$RelativeOutputPath\winapp-$Version.vsix"
222+
npx vsce package --no-dependencies -o "$RelativeOutputPath\winapp-$Version.vsix"
238223
$PackResult = $LASTEXITCODE
239224

240225
# Restore original package.json

scripts/start-vsc-release.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ try {
183183

184184
# 6. Confirm with user
185185
Write-Host ""
186+
186187
Write-Host " VSC Extension Release Plan" -ForegroundColor White
187188
Write-Host " ─────────────────────────────────────────────" -ForegroundColor White
188189
Write-Host " Release version : $releaseVersion" -ForegroundColor White

src/winapp-VSC/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ The **WinApp** extension brings the [Windows App Development CLI (WinApp CLI)](h
66
77
## Get Started
88

9-
> [!IMPORTANT]
10-
> The WinApp VS Code Extension is not yet available in the VS Code Marketplace. We plan to publish the extension publicly soon.
9+
> The WinApp VS Code Extension is not yet available in the VS Code Marketplace. We plan to publish the extension publicly soon.
1110
1211
Try the WinApp extension today by downloading our latest prerelease: [**VS Code Extension**](https://nightly.link/microsoft/WinAppCli/workflows/build-package/main/vscode-extension.zip)
1312

@@ -55,10 +54,8 @@ The extension provides a **custom `winapp` debug type** that launches your app w
5554
4. It launches your app via `winapp run` to give it package identity.
5655
5. A child debug session attaches to the running process using the debugger you specified.
5756

58-
> [!IMPORTANT]
5957
> The `winapp` debug type assumes your project has already been built and that a build output folder containing an `.exe` exists in your project. It **does not** build your project automatically — so after making code changes, you must rebuild your project before launching to see those changes reflected in the running app.
6058
61-
> [!TIP]
6259
> You can automate the build step by adding a `preLaunchTask` to your `launch.json` configuration. This tells VS Code to run a build task before every debug session, so your changes are always compiled before launch.
6360
>
6461
> 1. Define a build task in `.vscode/tasks.json` (example for .NET):

0 commit comments

Comments
 (0)