diff --git a/tasks/tags/createTags.ts b/tasks/tags/createTags.ts index 9a561209b..8b010cd5d 100644 --- a/tasks/tags/createTags.ts +++ b/tasks/tags/createTags.ts @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 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'; import { PlatformInformation } from '../../src/shared/platform'; import path from 'path'; import { runTask } from '../runTask'; +import { rootPath } from '../projectPaths'; runTask(createTags); @@ -34,8 +36,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 +185,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 +237,48 @@ async function getCommitFromNugetAsync( console.log(`commitNumber is ${commitNumber}`); return commitNumber; } + +function getPackageJsonFromReleaseCommit(releaseCommit: string): { defaults?: { [key: string]: string } } | null { + const packageJsonPath = 'package.json'; + + try { + // 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) { + 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 gitCommand = `git ${args.join(' ')}`; + const cwd = rootPath; + const result = spawnSync('git', args, { encoding: 'utf8', 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; + } + + return result.stdout.trim(); +}