Use PR-specific version for dogfood VS Code extension#15892
Use PR-specific version for dogfood VS Code extension#15892adamint wants to merge 3 commits intomicrosoft:mainfrom
Conversation
For PR builds, set the extension VSIX version to 0.0.<PR_NUMBER> so dogfooded extensions are clearly distinguishable from marketplace releases. The version override flows from ci.yml through tests.yml to the vsce package command. Also support ExtensionVersionOverride MSBuild property in Extension.proj for local builds (e.g. dotnet build /p:ExtensionVersionOverride=0.0.99). Fixes microsoft#15589
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15892Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15892" |
vsce interprets --version as 'print tool version'. The package version must be passed as a positional argument: vsce package <version>.
There was a problem hiding this comment.
Pull request overview
Updates the VS Code extension build/packaging pipeline so PR dogfood builds can use a PR-specific extension version (intended as 0.0.<PR_NUMBER>) instead of the Marketplace package.json version, making dogfooded builds distinguishable.
Changes:
- Add an
EXTENSION_VERSION_OVERRIDEoutput inci.ymlfor PR runs and pass it into the reusabletests.ymlworkflow. - Add a
extensionVersionOverrideinput totests.ymland thread it into the VSIX packaging command. - Add an
ExtensionVersionOverrideMSBuild property toextension/Extension.projto influence VSIX artifact naming and intended packaging behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
.github/workflows/ci.yml |
Computes and forwards an extension version override for PR builds. |
.github/workflows/tests.yml |
Accepts the override input and attempts to pass it to vsce package during VSIX creation. |
extension/Extension.proj |
Adds an override property intended to affect the packaged VSIX version and output artifact naming. |
vsce package does not have a --version flag for setting the package version (--version prints the tool version). The [version] positional arg triggers npm version bump semantics, not an explicit version set. Instead, use 'npm version --no-git-tag-version' in CI and 'node -e' in Extension.proj to update package.json before packaging.
| Write-Host "Computed VERSION_SUFFIX_OVERRIDE=$VERSION_SUFFIX" | ||
| "VERSION_SUFFIX_OVERRIDE=$VERSION_SUFFIX" | Out-File -FilePath $Env:GITHUB_OUTPUT -Append -Encoding utf8 | ||
|
|
||
| $EXTENSION_VERSION = "0.0.$($Env:PR_NUMBER)" |
There was a problem hiding this comment.
What happens if someone already has the marketplace build installed and then dogfoods this PR? VS Code's pre-release docs say it always updates extensions to the highest version available, and it explicitly recommends keeping pre-release versions numerically above the release track. Because this resets the PR build to 0.0.<PR>, any existing Aspire release like 1.0.7 outranks it, so brownfield users can be moved back to stable even though they intentionally installed the PR extension. That makes the dogfood path unreliable for existing users and conflicts with the sibling VS Code contract for pre-release versioning. Likely fix: derive the PR version from the current release line and keep it numerically above stable (for example, an odd/even track), rather than forcing 0.0.x.
| </PropertyGroup> | ||
|
|
||
| <!-- Override package.json version if ExtensionVersionOverride is set --> | ||
| <Exec Command="node -e "const p=require('./package.json');p.version='$(ExtensionVersionOverride)';require('fs').writeFileSync('./package.json',JSON.stringify(p,null,2)+'\n')"" |
There was a problem hiding this comment.
What happens if a maintainer runs the documented local command dotnet build Extension.proj /p:ExtensionVersionOverride=0.0.99 and then does a normal build from the same checkout? This step rewrites the tracked extension/package.json in place and never restores it. After that the tree stays dirty, and the next non-override build reads 0.0.99 back as the source version, so it keeps producing dogfood-versioned VSIXes until the file is manually reset. That's a hidden contract violation in the new local-build path, not just a cosmetic diff. Likely fix: package from a temp/staging copy or restore the original package.json after vsce runs.
JamesNK
left a comment
There was a problem hiding this comment.
Two low-severity hardening suggestions around input interpolation in shell/JS contexts. The core logic looks correct.
| run: npm test | ||
| - name: Override extension version for PR builds | ||
| if: ${{ inputs.extensionVersionOverride != '' }} | ||
| run: npm version "${{ inputs.extensionVersionOverride }}" --no-git-tag-version |
There was a problem hiding this comment.
Low-risk expression injection: ${{ inputs.extensionVersionOverride }} is interpolated directly into the run: shell script. While the source (github.event.number) is GitHub-controlled, direct interpolation in run: blocks is a documented anti-pattern. Assigning to an env var first avoids the class of issue entirely:
- name: Override extension version for PR builds
if: ${{ inputs.extensionVersionOverride != '' }}
env:
EXTENSION_VERSION: ${{ inputs.extensionVersionOverride }}
run: npm version "$EXTENSION_VERSION" --no-git-tag-version| </PropertyGroup> | ||
|
|
||
| <!-- Override package.json version if ExtensionVersionOverride is set --> | ||
| <Exec Command="node -e "const p=require('./package.json');p.version='$(ExtensionVersionOverride)';require('fs').writeFileSync('./package.json',JSON.stringify(p,null,2)+'\n')"" |
There was a problem hiding this comment.
Low-risk command injection: $(ExtensionVersionOverride) is interpolated directly into a node -e JavaScript string literal. A value containing a single quote (') would break the JS syntax and could inject arbitrary Node code — e.g., /p:ExtensionVersionOverride="a';process.exit(1);//". The input is developer-controlled so the practical risk is low, but it can be hardened by passing the version via an environment variable:
<Exec Command="node -e "const p=require('./package.json');p.version=process.env.EXT_VER;require('fs').writeFileSync('./package.json',JSON.stringify(p,null,2)+'\n')""
EnvironmentVariables="EXT_VER=$(ExtensionVersionOverride)"
Condition="'$(ExtensionVersionOverride)' != ''"
WorkingDirectory="$(ExtensionSrcDir)" />
Description
When installing the VS Code extension from a PR dogfood build, the version is always the same as the marketplace release (currently
1.0.7frompackage.json), making it impossible to distinguish a dogfooded extension from a released one.This PR sets the extension VSIX version to
0.0.<PR_NUMBER>for PR builds, so dogfooded extensions are clearly distinguishable from marketplace releases. The version0.0.Xwas chosen because:0.0.Xis obviously non-release (major=minor=0)Changes
ci.yml: ComputeEXTENSION_VERSION_OVERRIDE=0.0.<PR_NUMBER>alongside the existingVERSION_SUFFIX_OVERRIDEand pass it totests.ymltests.yml: AcceptextensionVersionOverrideinput and pass--versiontovsce packagewhen setExtension.proj: SupportExtensionVersionOverrideMSBuild property for local builds (dotnet build Extension.proj /p:ExtensionVersionOverride=0.0.99)Non-PR builds (push to main/release) continue using the version from
package.json.Fixes #15589
Checklist