From 927a2a6a8c51aec879a1f18e62ffa6601f78d738 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 17 Jun 2026 17:20:20 -0700 Subject: [PATCH 1/3] Use local checkout for fetching package.json instead of accessing github directly --- tasks/tags/createTags.ts | 70 ++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/tasks/tags/createTags.ts b/tasks/tags/createTags.ts index 9a561209b..0922fab08 100644 --- a/tasks/tags/createTags.ts +++ b/tasks/tags/createTags.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; +import { spawnSync } from 'child_process'; import minimist from 'minimist'; import { Octokit } from '@octokit/rest'; import { allNugetPackages, NugetPackageInfo, platformSpecificPackages } from '../packaging/offlinePackagingTasks'; @@ -34,8 +35,8 @@ async function createTagsRoslyn(): Promise { options, 'dotnet', 'roslyn', - async (releaseCommit: string, githubPAT: string) => - getCommitFromNugetAsync(allNugetPackages.roslyn, releaseCommit, githubPAT), + async (releaseCommit: string, _githubPAT: string) => + getCommitFromNugetAsync(allNugetPackages.roslyn, releaseCommit), (releaseVersion: string, isPrerelease: boolean): [string, string] => { const prereleaseText = isPrerelease ? '-prerelease' : ''; return [ @@ -183,32 +184,9 @@ function logError(message: string): void { console.log(`##vso[task.logissue type=error]${message}`); } -async function getCommitFromNugetAsync( - packageInfo: NugetPackageInfo, - releaseCommit: string, - githubPAT: string -): Promise { - // Fetch package.json from dotnet/vscode-csharp GitHub repo at the specific commit - const packageJsonUrl = `https://raw.githubusercontent.com/dotnet/vscode-csharp/${releaseCommit}/package.json`; - - console.log(`Fetching package.json from ${packageJsonUrl}`); - - let packageJson: { defaults?: { [key: string]: string } }; - try { - const response = await fetch(packageJsonUrl, { - headers: { - Authorization: `token ${githubPAT}`, - Accept: 'application/vnd.github.v3.raw', - }, - }); - if (!response.ok) { - logError(`Failed to fetch package.json from ${packageJsonUrl}: ${response.status} ${response.statusText}`); - return null; - } - const packageJsonString = await response.text(); - packageJson = JSON.parse(packageJsonString); - } catch (error) { - logError(`Error fetching package.json from GitHub: ${error}`); +async function getCommitFromNugetAsync(packageInfo: NugetPackageInfo, releaseCommit: string): Promise { + const packageJson = getPackageJsonFromReleaseCommit(releaseCommit); + if (!packageJson) { return null; } @@ -258,3 +236,39 @@ async function getCommitFromNugetAsync( console.log(`commitNumber is ${commitNumber}`); return commitNumber; } + +function getPackageJsonFromReleaseCommit(releaseCommit: string): { defaults?: { [key: string]: string } } | null { + const packageJsonPath = 'package.json'; + const normalizedReleaseCommit = releaseCommit.trim().toLowerCase(); + + try { + const headCommit = getGitOutput(['rev-parse', 'HEAD']); + if (headCommit?.toLowerCase() === normalizedReleaseCommit) { + console.log(`Reading package.json from checked-out commit ${releaseCommit}`); + return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + } + + console.log(`Reading package.json from local git object ${releaseCommit}:${packageJsonPath}`); + const packageJsonString = getGitOutput(['show', `${releaseCommit}:${packageJsonPath}`]); + if (!packageJsonString) { + logError( + `Failed to read package.json from local git commit ${releaseCommit}. Ensure the release commit is fetched or checked out.` + ); + return null; + } + + return JSON.parse(packageJsonString); + } catch (error) { + logError(`Error reading package.json for commit ${releaseCommit}: ${error}`); + return null; + } +} + +function getGitOutput(args: string[]): string | null { + const result = spawnSync('git', args, { encoding: 'utf8' }); + if (result.status !== 0) { + return null; + } + + return result.stdout.trim(); +} From bdac9acfa3bbda759377a684a145d388f0492500 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 17 Jun 2026 17:31:11 -0700 Subject: [PATCH 2/3] cleanup --- .vscode/settings.json | 3 +++ tasks/tags/createTags.ts | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3a3cab8ed..d0bfee3ec 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,4 +22,7 @@ "eslint.lintTask.enable": true, "dotnet.defaultSolution": "disable", "jest.runMode": "on-demand", + "chat.tools.terminal.autoApprove": { + "npx eslint": true + }, } diff --git a/tasks/tags/createTags.ts b/tasks/tags/createTags.ts index 0922fab08..0394fecbb 100644 --- a/tasks/tags/createTags.ts +++ b/tasks/tags/createTags.ts @@ -266,7 +266,19 @@ function getPackageJsonFromReleaseCommit(releaseCommit: string): { defaults?: { function getGitOutput(args: string[]): string | null { const result = spawnSync('git', args, { encoding: 'utf8' }); + const gitCommand = `git ${args.join(' ')}`; + const cwd = process.cwd(); + + if (result.error) { + logError(`Failed to run '${gitCommand}' from '${cwd}': ${result.error.message}`); + return null; + } + if (result.status !== 0) { + const stderr = result.stderr.trim(); + const stdout = result.stdout.trim(); + const failureDetails = stderr || stdout || `Exited with status ${result.status}.`; + logError(`Command '${gitCommand}' failed from '${cwd}': ${failureDetails}`); return null; } From be401d2af5fde906e117a4384fdbfc4e672bddd4 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Fri, 19 Jun 2026 11:25:47 -0700 Subject: [PATCH 3/3] feedback --- .vscode/settings.json | 3 --- tasks/tags/createTags.ts | 16 +++++++--------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d0bfee3ec..3a3cab8ed 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,7 +22,4 @@ "eslint.lintTask.enable": true, "dotnet.defaultSolution": "disable", "jest.runMode": "on-demand", - "chat.tools.terminal.autoApprove": { - "npx eslint": true - }, } diff --git a/tasks/tags/createTags.ts b/tasks/tags/createTags.ts index 0394fecbb..8b010cd5d 100644 --- a/tasks/tags/createTags.ts +++ b/tasks/tags/createTags.ts @@ -11,6 +11,7 @@ import { allNugetPackages, NugetPackageInfo, platformSpecificPackages } from '.. import { PlatformInformation } from '../../src/shared/platform'; import path from 'path'; import { runTask } from '../runTask'; +import { rootPath } from '../projectPaths'; runTask(createTags); @@ -239,15 +240,12 @@ async function getCommitFromNugetAsync(packageInfo: NugetPackageInfo, releaseCom function getPackageJsonFromReleaseCommit(releaseCommit: string): { defaults?: { [key: string]: string } } | null { const packageJsonPath = 'package.json'; - const normalizedReleaseCommit = releaseCommit.trim().toLowerCase(); try { - const headCommit = getGitOutput(['rev-parse', 'HEAD']); - if (headCommit?.toLowerCase() === normalizedReleaseCommit) { - console.log(`Reading package.json from checked-out commit ${releaseCommit}`); - return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); - } - + // Read the committed package.json at the release commit directly from the local git object + // database. The release pipeline fetches full history (fetchDepth: 0) and checks out the + // release commit, so the object is always present. Reading the committed blob (rather than the + // working tree) ensures the tag references exactly what was released. console.log(`Reading package.json from local git object ${releaseCommit}:${packageJsonPath}`); const packageJsonString = getGitOutput(['show', `${releaseCommit}:${packageJsonPath}`]); if (!packageJsonString) { @@ -265,9 +263,9 @@ function getPackageJsonFromReleaseCommit(releaseCommit: string): { defaults?: { } function getGitOutput(args: string[]): string | null { - const result = spawnSync('git', args, { encoding: 'utf8' }); const gitCommand = `git ${args.join(' ')}`; - const cwd = process.cwd(); + const cwd = rootPath; + const result = spawnSync('git', args, { encoding: 'utf8', cwd }); if (result.error) { logError(`Failed to run '${gitCommand}' from '${cwd}': ${result.error.message}`);