diff --git a/dist/tools/libs/gitversion.mjs b/dist/tools/libs/gitversion.mjs index 039029ba3..68b8ed7ad 100644 --- a/dist/tools/libs/gitversion.mjs +++ b/dist/tools/libs/gitversion.mjs @@ -1,8 +1,8 @@ +import * as path from 'node:path'; +import * as fs from 'node:fs/promises'; +import * as crypto from 'node:crypto'; import { S as SettingsProvider, D as DotnetTool, k as keysOf, A as ArgumentsBuilder, R as RunnerBase } from './tools.mjs'; -import 'node:crypto'; -import 'node:fs/promises'; import 'node:os'; -import 'node:path'; import './semver.mjs'; import { allIndexesOf } from '../lib.mjs'; @@ -63,9 +63,12 @@ class GitVersionTool extends DotnetTool { const settings = this.settingsProvider.getExecuteSettings(); const workDir = await this.getRepoDir(settings); await this.checkShallowClone(settings, workDir); - const args = await this.getExecuteArguments(workDir, settings); + const outputFile = path.join(this.buildAgent.tempDir, `gitversion-${crypto.randomUUID()}.json`); + this.buildAgent.debug(`Writing GitVersion variables to file: ${outputFile}`); + const args = await this.getExecuteArguments(workDir, settings, outputFile); await this.setDotnetRoot(); - return await this.executeTool(args); + const result = await this.executeTool(args); + return { ...result, outputFile }; } async executeCommand() { const settings = this.settingsProvider.getCommandSettings(); @@ -104,8 +107,14 @@ class GitVersionTool extends DotnetTool { async getRepoDir(settings) { return await super.getRepoPath(settings.targetPath); } - async getExecuteArguments(workDir, options) { - const builder = new ArgumentsBuilder().addArgument(workDir).addArgument("/output").addArgument("json").addArgument("/l").addArgument("console"); + async getExecuteArguments(workDir, options, outputFile) { + const builder = new ArgumentsBuilder().addArgument(workDir); + if (outputFile) { + builder.addArgument("/output").addArgument("file").addArgument("/outputfile").addArgument(outputFile); + } else { + builder.addArgument("/output").addArgument("json"); + } + builder.addArgument("/l").addArgument("console"); const { disableCache, disableNormalization, @@ -169,6 +178,13 @@ class GitVersionTool extends DotnetTool { } } } + async readGitVersionOutput(outputFile) { + const content = await fs.readFile(outputFile, "utf8"); + const output = JSON.parse(content); + await fs.unlink(outputFile).catch(() => { + }); + return output; + } toCamelCase(input) { return input.replace(/^\w|[A-Z]|\b\w|\s+/g, function(match, index) { if (+match === 0) return ""; @@ -203,33 +219,49 @@ class Runner extends RunnerBase { async execute() { return this.safeExecute(async () => { const result = await this.tool.executeJson(); - return this.processGitVersionOutput(result); + return await this.processGitVersionOutput(result); }, "GitVersion executed successfully"); } async command() { return this.safeExecute(async () => await this.tool.executeCommand(), "GitVersion executed successfully"); } - processGitVersionOutput(result) { - this.buildAgent.debug("Parsing GitVersion output"); + async processGitVersionOutput(result) { + this.buildAgent.debug("Processing GitVersion output"); if (result.code !== 0) { return result; } - const stdout = result.stdout; - const gitVersionOutput = this.extractGitVersionOutput(stdout); + let gitVersionOutput = null; + if (result.outputFile) { + this.buildAgent.debug(`Reading GitVersion variables from file: ${result.outputFile}`); + try { + gitVersionOutput = await this.tool.readGitVersionOutput(result.outputFile); + } catch (error) { + return this.handleOutputError(`Failed to read or parse GitVersion variables file: ${this.getErrorMessage(error)}`); + } + } else { + this.buildAgent.debug("Parsing GitVersion output from stdout"); + const stdout = result.stdout; + gitVersionOutput = this.extractGitVersionOutput(stdout); + } if (gitVersionOutput === null) { - const errorMessage = "GitVersion output is not valid JSON, see output details"; - this.buildAgent.debug(errorMessage); - this.buildAgent.setFailed(errorMessage, true); - return { - code: -1, - error: new Error(errorMessage) - }; + return this.handleOutputError("GitVersion output is not valid JSON, see output details"); } this.tool.writeGitVersionToAgent(gitVersionOutput); this.tool.updateBuildNumber(); this.buildAgent.setSucceeded("GitVersion executed successfully", true); return result; } + getErrorMessage(error) { + return error instanceof Error ? error.message : String(error); + } + handleOutputError(message) { + this.buildAgent.debug(message); + this.buildAgent.setFailed(message, true); + return { + code: -1, + error: new Error(message) + }; + } /** * Attempts to extract and parse a JSON object representing `GitVersionOutput` from the given input string. * The method assumes the last closing curly brace (`}`) in the input belongs to the end of the JSON object, diff --git a/dist/tools/libs/gitversion.mjs.map b/dist/tools/libs/gitversion.mjs.map index b0567b491..e22633e94 100644 --- a/dist/tools/libs/gitversion.mjs.map +++ b/dist/tools/libs/gitversion.mjs.map @@ -1 +1 @@ -{"version":3,"file":"gitversion.mjs","sources":["../../../src/tools/gitversion/settings.ts","../../../src/tools/gitversion/tool.ts","../../../src/tools/gitversion/runner.ts"],"sourcesContent":["import { type ISettingsProvider, SettingsProvider } from '@tools/common'\nimport { type CommandSettings, type ExecuteSettings } from './models'\n\nexport interface IGitVersionSettingsProvider extends ISettingsProvider {\n getExecuteSettings(): ExecuteSettings\n\n getCommandSettings(): CommandSettings\n}\n\nexport class GitVersionSettingsProvider extends SettingsProvider implements IGitVersionSettingsProvider {\n getExecuteSettings(): ExecuteSettings {\n const targetPath = this.buildAgent.getInput('targetPath')\n\n const disableCache = this.buildAgent.getBooleanInput('disableCache')\n const disableNormalization = this.buildAgent.getBooleanInput('disableNormalization')\n const disableShallowCloneCheck = this.buildAgent.getBooleanInput('disableShallowCloneCheck')\n\n const configFilePath = this.buildAgent.getInput('configFilePath', false)\n const overrideConfig = this.buildAgent.getListInput('overrideConfig', false)\n\n const updateAssemblyInfo = this.buildAgent.getBooleanInput('updateAssemblyInfo')\n const updateAssemblyInfoFilename = this.buildAgent.getInput('updateAssemblyInfoFilename')\n\n const updateProjectFiles = this.buildAgent.getBooleanInput('updateProjectFiles')\n\n const buildNumberFormat = this.buildAgent.getInput('buildNumberFormat', false)\n\n return {\n targetPath,\n disableCache,\n disableNormalization,\n disableShallowCloneCheck,\n configFilePath,\n overrideConfig,\n updateAssemblyInfo,\n updateAssemblyInfoFilename,\n updateProjectFiles,\n buildNumberFormat\n }\n }\n\n getCommandSettings(): CommandSettings {\n const targetPath = this.buildAgent.getInput('targetPath')\n const disableShallowCloneCheck = this.buildAgent.getBooleanInput('disableShallowCloneCheck')\n const args = this.buildAgent.getInput('arguments')\n\n return {\n targetPath,\n disableShallowCloneCheck,\n arguments: args\n }\n }\n}\n","import { type ExecResult } from '@agents/common'\nimport { ArgumentsBuilder, DotnetTool, keysOf } from '@tools/common'\nimport { type CommandSettings, type ExecuteSettings, type GitVersionOutput } from './models'\nimport { GitVersionSettingsProvider, type IGitVersionSettingsProvider } from './settings'\n\nexport class GitVersionTool extends DotnetTool {\n get packageName(): string {\n return 'GitVersion.Tool'\n }\n\n get toolName(): string {\n return 'dotnet-gitversion'\n }\n\n get toolPathVariable(): string {\n return 'GITVERSION_PATH'\n }\n\n get versionRange(): string | null {\n return '>=6.1.0 <7.0.0'\n }\n\n get settingsProvider(): IGitVersionSettingsProvider {\n return new GitVersionSettingsProvider(this.buildAgent)\n }\n\n async executeJson(): Promise {\n const settings = this.settingsProvider.getExecuteSettings()\n const workDir = await this.getRepoDir(settings)\n\n await this.checkShallowClone(settings, workDir)\n\n const args = await this.getExecuteArguments(workDir, settings)\n\n await this.setDotnetRoot()\n return await this.executeTool(args)\n }\n\n async executeCommand(): Promise {\n const settings = this.settingsProvider.getCommandSettings()\n const workDir = await this.getRepoDir(settings)\n\n await this.checkShallowClone(settings, workDir)\n\n const args = this.getCommandArguments(workDir, settings)\n\n await this.setDotnetRoot()\n return await this.executeTool(args)\n }\n\n writeGitVersionToAgent(output: GitVersionOutput): void {\n for (const property of keysOf(output)) {\n const name = this.toCamelCase(property)\n try {\n let value = output[property]?.toString()\n if (value === '0') {\n value = '0'\n }\n this.buildAgent.setOutput(name, value)\n this.buildAgent.setOutput(`GitVersion_${property}`, value)\n this.buildAgent.setVariable(name, value)\n this.buildAgent.setVariable(`GitVersion_${property}`, value)\n } catch (_error) {\n this.buildAgent.error(`Unable to set output/variable for ${property}`)\n }\n }\n }\n\n updateBuildNumber(): void {\n const settings = this.settingsProvider.getExecuteSettings()\n if (settings.buildNumberFormat) {\n const buildNumber = this.buildAgent.getExpandedString(settings.buildNumberFormat)\n this.buildAgent.updateBuildNumber(buildNumber)\n } else {\n this.buildAgent.debug('No buildNumberFormat provided. Skipping build number update.')\n }\n }\n\n protected async getRepoDir(settings: ExecuteSettings | CommandSettings): Promise {\n return await super.getRepoPath(settings.targetPath)\n }\n\n protected async getExecuteArguments(workDir: string, options: ExecuteSettings): Promise {\n const builder = new ArgumentsBuilder().addArgument(workDir).addArgument('/output').addArgument('json').addArgument('/l').addArgument('console')\n\n const {\n disableCache,\n disableNormalization,\n configFilePath,\n overrideConfig,\n updateAssemblyInfo,\n updateAssemblyInfoFilename,\n updateProjectFiles\n //\n } = options\n\n if (disableCache) {\n builder.addArgument('/nocache')\n }\n\n if (disableNormalization) {\n builder.addArgument('/nonormalize')\n }\n\n if (configFilePath) {\n if (await this.isValidInputFile(workDir, configFilePath)) {\n builder.addArgument('/config').addArgument(configFilePath)\n } else {\n throw new Error(`GitVersion configuration file not found at ${configFilePath}`)\n }\n }\n\n if (overrideConfig) {\n for (let config of overrideConfig) {\n config = config.trim()\n if (config.match(/([a-zA-Z0-9]+(-[a-zA-Z]+)*=[a-zA-Z0-9\\- :.']*)/)) {\n builder.addArgument('/overrideconfig').addArgument(config)\n }\n }\n }\n\n if (updateAssemblyInfo) {\n builder.addArgument('/updateassemblyinfo')\n\n // You can specify 'updateAssemblyInfo' without 'updateAssemblyInfoFilename'.\n if (updateAssemblyInfoFilename) {\n if (await this.isValidInputFile(workDir, updateAssemblyInfoFilename)) {\n builder.addArgument(updateAssemblyInfoFilename)\n } else {\n throw new Error(`AssemblyInfoFilename file not found at ${updateAssemblyInfoFilename}`)\n }\n }\n }\n\n if (updateProjectFiles) {\n builder.addArgument('/updateprojectfiles')\n }\n\n return builder.build()\n }\n\n protected getCommandArguments(workDir: string, options: CommandSettings): string[] {\n const builder = new ArgumentsBuilder().addArgument(workDir)\n\n if (options.arguments) {\n builder.addArguments(ArgumentsBuilder.parseArgumentString(options.arguments))\n }\n\n return builder.build()\n }\n\n private async checkShallowClone(settings: ExecuteSettings | CommandSettings, workDir: string): Promise {\n if (!settings.disableShallowCloneCheck) {\n const isShallowResult = await this.execute('git', ['-C', workDir, 'rev-parse', '--is-shallow-repository'])\n if (isShallowResult.code === 0 && isShallowResult.stdout?.trim() === 'true') {\n throw new Error(\n 'The repository is shallow. Consider disabling shallow clones. See https://github.com/GitTools/actions/blob/main/docs/cloning.md for more information.'\n )\n }\n }\n }\n\n private toCamelCase(input: string): string {\n return input.replace(/^\\w|[A-Z]|\\b\\w|\\s+/g, function (match, index) {\n if (+match === 0) return '' // or if (/\\s+/.test(match)) for white spaces\n return index === 0 ? match.toLowerCase() : match.toUpperCase()\n })\n }\n}\n","import { type ExecResult, type IBuildAgent } from '@agents/common'\nimport { type Commands, type GitVersionOutput } from './models'\nimport { GitVersionTool } from './tool'\nimport { RunnerBase } from '../common/runner'\nimport { allIndexesOf } from '@lib'\n\nexport class Runner extends RunnerBase {\n protected readonly tool: GitVersionTool\n\n constructor(protected readonly buildAgent: IBuildAgent) {\n super(buildAgent)\n this.tool = new GitVersionTool(this.buildAgent)\n }\n\n async run(command: Commands): Promise {\n switch (command) {\n case 'setup':\n return await this.setup()\n case 'execute':\n return await this.execute()\n case 'command':\n return await this.command()\n }\n }\n\n private async setup(): Promise {\n return this.safeExecute(async () => {\n await this.tool.install()\n return { code: 0 }\n }, 'GitVersion setup successfully')\n }\n\n private async execute(): Promise {\n return this.safeExecute(async () => {\n const result = await this.tool.executeJson()\n return this.processGitVersionOutput(result)\n }, 'GitVersion executed successfully')\n }\n\n private async command(): Promise {\n return this.safeExecute(async () => await this.tool.executeCommand(), 'GitVersion executed successfully')\n }\n\n private processGitVersionOutput(result: ExecResult): ExecResult {\n this.buildAgent.debug('Parsing GitVersion output')\n\n // Return error to be handled by calling function\n if (result.code !== 0) {\n return result\n }\n\n const stdout = result.stdout as string\n const gitVersionOutput = this.extractGitVersionOutput(stdout)\n\n if (gitVersionOutput === null) {\n const errorMessage = 'GitVersion output is not valid JSON, see output details'\n this.buildAgent.debug(errorMessage)\n this.buildAgent.setFailed(errorMessage, true)\n return {\n code: -1,\n error: new Error(errorMessage)\n }\n }\n\n this.tool.writeGitVersionToAgent(gitVersionOutput)\n this.tool.updateBuildNumber()\n this.buildAgent.setSucceeded('GitVersion executed successfully', true)\n return result\n }\n\n /**\n * Attempts to extract and parse a JSON object representing `GitVersionOutput` from the given input string.\n * The method assumes the last closing curly brace (`}`) in the input belongs to the end of the JSON object,\n * and iteratively expands the search area backwards from each opening curly brace (`{`) until a valid JSON object is found.\n * If parsing fails, it logs debug information and continues searching until all possible start positions are exhausted.\n *\n * @param input - The string containing the potential JSON output from GitVersion.\n * @returns The parsed `GitVersionOutput` object if extraction and parsing succeed; otherwise, `null`.\n */\n private extractGitVersionOutput(input: string): GitVersionOutput | null {\n const allStartOfJsonIndexes = allIndexesOf(input, '{')\n // Assumed last '}' character will belong to the JSON object\n const endOfJsonIndex = input.lastIndexOf('}') + 1\n\n // Early return if no '{' or '}' found\n if (allStartOfJsonIndexes.length === 0) {\n this.buildAgent.debug(\"No opening curly brace '{' found in input; cannot extract JSON.\")\n return null\n }\n if (endOfJsonIndex === 0) {\n this.buildAgent.debug(\"No closing curly brace '}' found in input; cannot extract JSON.\")\n return null\n }\n\n // Start from the bottom when searching for the JSON object\n let startIndexArrayPos = allStartOfJsonIndexes.length - 1\n let decodePassCount = 1\n\n let currSearchString = input.substring(allStartOfJsonIndexes[startIndexArrayPos], endOfJsonIndex)\n let resultJson = null\n\n while (resultJson === null && startIndexArrayPos >= 0) {\n try {\n this.buildAgent.debug(`Starting JSON extraction at ${allStartOfJsonIndexes[startIndexArrayPos]} to ${endOfJsonIndex}`)\n\n resultJson = JSON.parse(currSearchString) as GitVersionOutput\n } catch (ex) {\n let exObject = new Error('Unable to parse exception object')\n\n if (ex instanceof Error) {\n exObject = ex\n }\n\n const errorMessage = `Failed to parse JSON object on pass ${decodePassCount}. Expanding search area from string index ${allStartOfJsonIndexes[startIndexArrayPos]} to ${endOfJsonIndex}. \\nPrevious search area:'${currSearchString}' \\nCaught Exception: ${exObject.message}`\n this.buildAgent.debug(errorMessage)\n\n // Expand search area\n decodePassCount++\n startIndexArrayPos--\n currSearchString = input.substring(allStartOfJsonIndexes[startIndexArrayPos], endOfJsonIndex)\n }\n }\n\n return resultJson\n }\n}\n"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"gitversion.mjs","sources":["../../../src/tools/gitversion/settings.ts","../../../src/tools/gitversion/tool.ts","../../../src/tools/gitversion/runner.ts"],"sourcesContent":["import { type ISettingsProvider, SettingsProvider } from '@tools/common'\nimport { type CommandSettings, type ExecuteSettings } from './models'\n\nexport interface IGitVersionSettingsProvider extends ISettingsProvider {\n getExecuteSettings(): ExecuteSettings\n\n getCommandSettings(): CommandSettings\n}\n\nexport class GitVersionSettingsProvider extends SettingsProvider implements IGitVersionSettingsProvider {\n getExecuteSettings(): ExecuteSettings {\n const targetPath = this.buildAgent.getInput('targetPath')\n\n const disableCache = this.buildAgent.getBooleanInput('disableCache')\n const disableNormalization = this.buildAgent.getBooleanInput('disableNormalization')\n const disableShallowCloneCheck = this.buildAgent.getBooleanInput('disableShallowCloneCheck')\n\n const configFilePath = this.buildAgent.getInput('configFilePath', false)\n const overrideConfig = this.buildAgent.getListInput('overrideConfig', false)\n\n const updateAssemblyInfo = this.buildAgent.getBooleanInput('updateAssemblyInfo')\n const updateAssemblyInfoFilename = this.buildAgent.getInput('updateAssemblyInfoFilename')\n\n const updateProjectFiles = this.buildAgent.getBooleanInput('updateProjectFiles')\n\n const buildNumberFormat = this.buildAgent.getInput('buildNumberFormat', false)\n\n return {\n targetPath,\n disableCache,\n disableNormalization,\n disableShallowCloneCheck,\n configFilePath,\n overrideConfig,\n updateAssemblyInfo,\n updateAssemblyInfoFilename,\n updateProjectFiles,\n buildNumberFormat\n }\n }\n\n getCommandSettings(): CommandSettings {\n const targetPath = this.buildAgent.getInput('targetPath')\n const disableShallowCloneCheck = this.buildAgent.getBooleanInput('disableShallowCloneCheck')\n const args = this.buildAgent.getInput('arguments')\n\n return {\n targetPath,\n disableShallowCloneCheck,\n arguments: args\n }\n }\n}\n","import * as path from 'node:path'\nimport * as fs from 'node:fs/promises'\nimport * as crypto from 'node:crypto'\nimport { type ExecResult } from '@agents/common'\nimport { ArgumentsBuilder, DotnetTool, keysOf } from '@tools/common'\nimport { type CommandSettings, type ExecuteSettings, type GitVersionOutput } from './models'\nimport { GitVersionSettingsProvider, type IGitVersionSettingsProvider } from './settings'\n\nexport class GitVersionTool extends DotnetTool {\n get packageName(): string {\n return 'GitVersion.Tool'\n }\n\n get toolName(): string {\n return 'dotnet-gitversion'\n }\n\n get toolPathVariable(): string {\n return 'GITVERSION_PATH'\n }\n\n get versionRange(): string | null {\n return '>=6.1.0 <7.0.0'\n }\n\n get settingsProvider(): IGitVersionSettingsProvider {\n return new GitVersionSettingsProvider(this.buildAgent)\n }\n\n async executeJson(): Promise {\n const settings = this.settingsProvider.getExecuteSettings()\n const workDir = await this.getRepoDir(settings)\n\n await this.checkShallowClone(settings, workDir)\n\n const outputFile = path.join(this.buildAgent.tempDir, `gitversion-${crypto.randomUUID()}.json`)\n this.buildAgent.debug(`Writing GitVersion variables to file: ${outputFile}`)\n const args = await this.getExecuteArguments(workDir, settings, outputFile)\n\n await this.setDotnetRoot()\n const result = await this.executeTool(args)\n return { ...result, outputFile }\n }\n\n async executeCommand(): Promise {\n const settings = this.settingsProvider.getCommandSettings()\n const workDir = await this.getRepoDir(settings)\n\n await this.checkShallowClone(settings, workDir)\n\n const args = this.getCommandArguments(workDir, settings)\n\n await this.setDotnetRoot()\n return await this.executeTool(args)\n }\n\n writeGitVersionToAgent(output: GitVersionOutput): void {\n for (const property of keysOf(output)) {\n const name = this.toCamelCase(property)\n try {\n let value = output[property]?.toString()\n if (value === '0') {\n value = '0'\n }\n this.buildAgent.setOutput(name, value)\n this.buildAgent.setOutput(`GitVersion_${property}`, value)\n this.buildAgent.setVariable(name, value)\n this.buildAgent.setVariable(`GitVersion_${property}`, value)\n } catch (_error) {\n this.buildAgent.error(`Unable to set output/variable for ${property}`)\n }\n }\n }\n\n updateBuildNumber(): void {\n const settings = this.settingsProvider.getExecuteSettings()\n if (settings.buildNumberFormat) {\n const buildNumber = this.buildAgent.getExpandedString(settings.buildNumberFormat)\n this.buildAgent.updateBuildNumber(buildNumber)\n } else {\n this.buildAgent.debug('No buildNumberFormat provided. Skipping build number update.')\n }\n }\n\n protected async getRepoDir(settings: ExecuteSettings | CommandSettings): Promise {\n return await super.getRepoPath(settings.targetPath)\n }\n\n protected async getExecuteArguments(workDir: string, options: ExecuteSettings, outputFile?: string): Promise {\n const builder = new ArgumentsBuilder().addArgument(workDir)\n\n if (outputFile) {\n builder.addArgument('/output').addArgument('file').addArgument('/outputfile').addArgument(outputFile)\n } else {\n builder.addArgument('/output').addArgument('json')\n }\n\n builder.addArgument('/l').addArgument('console')\n\n const {\n disableCache,\n disableNormalization,\n configFilePath,\n overrideConfig,\n updateAssemblyInfo,\n updateAssemblyInfoFilename,\n updateProjectFiles\n //\n } = options\n\n if (disableCache) {\n builder.addArgument('/nocache')\n }\n\n if (disableNormalization) {\n builder.addArgument('/nonormalize')\n }\n\n if (configFilePath) {\n if (await this.isValidInputFile(workDir, configFilePath)) {\n builder.addArgument('/config').addArgument(configFilePath)\n } else {\n throw new Error(`GitVersion configuration file not found at ${configFilePath}`)\n }\n }\n\n if (overrideConfig) {\n for (let config of overrideConfig) {\n config = config.trim()\n if (config.match(/([a-zA-Z0-9]+(-[a-zA-Z]+)*=[a-zA-Z0-9\\- :.']*)/)) {\n builder.addArgument('/overrideconfig').addArgument(config)\n }\n }\n }\n\n if (updateAssemblyInfo) {\n builder.addArgument('/updateassemblyinfo')\n\n // You can specify 'updateAssemblyInfo' without 'updateAssemblyInfoFilename'.\n if (updateAssemblyInfoFilename) {\n if (await this.isValidInputFile(workDir, updateAssemblyInfoFilename)) {\n builder.addArgument(updateAssemblyInfoFilename)\n } else {\n throw new Error(`AssemblyInfoFilename file not found at ${updateAssemblyInfoFilename}`)\n }\n }\n }\n\n if (updateProjectFiles) {\n builder.addArgument('/updateprojectfiles')\n }\n\n return builder.build()\n }\n\n protected getCommandArguments(workDir: string, options: CommandSettings): string[] {\n const builder = new ArgumentsBuilder().addArgument(workDir)\n\n if (options.arguments) {\n builder.addArguments(ArgumentsBuilder.parseArgumentString(options.arguments))\n }\n\n return builder.build()\n }\n\n private async checkShallowClone(settings: ExecuteSettings | CommandSettings, workDir: string): Promise {\n if (!settings.disableShallowCloneCheck) {\n const isShallowResult = await this.execute('git', ['-C', workDir, 'rev-parse', '--is-shallow-repository'])\n if (isShallowResult.code === 0 && isShallowResult.stdout?.trim() === 'true') {\n throw new Error(\n 'The repository is shallow. Consider disabling shallow clones. See https://github.com/GitTools/actions/blob/main/docs/cloning.md for more information.'\n )\n }\n }\n }\n\n async readGitVersionOutput(outputFile: string): Promise {\n const content = await fs.readFile(outputFile, 'utf8')\n const output = JSON.parse(content) as GitVersionOutput\n // Clean up the temporary file\n await fs.unlink(outputFile).catch(() => {\n // Ignore errors if file doesn't exist\n })\n return output\n }\n\n private toCamelCase(input: string): string {\n return input.replace(/^\\w|[A-Z]|\\b\\w|\\s+/g, function (match, index) {\n if (+match === 0) return '' // or if (/\\s+/.test(match)) for white spaces\n return index === 0 ? match.toLowerCase() : match.toUpperCase()\n })\n }\n}\n","import { type ExecResult, type IBuildAgent } from '@agents/common'\nimport { type Commands, type GitVersionOutput } from './models'\nimport { GitVersionTool } from './tool'\nimport { RunnerBase } from '../common/runner'\nimport { allIndexesOf } from '@lib'\n\nexport class Runner extends RunnerBase {\n protected readonly tool: GitVersionTool\n\n constructor(protected readonly buildAgent: IBuildAgent) {\n super(buildAgent)\n this.tool = new GitVersionTool(this.buildAgent)\n }\n\n async run(command: Commands): Promise {\n switch (command) {\n case 'setup':\n return await this.setup()\n case 'execute':\n return await this.execute()\n case 'command':\n return await this.command()\n }\n }\n\n private async setup(): Promise {\n return this.safeExecute(async () => {\n await this.tool.install()\n return { code: 0 }\n }, 'GitVersion setup successfully')\n }\n\n private async execute(): Promise {\n return this.safeExecute(async () => {\n const result = await this.tool.executeJson()\n return await this.processGitVersionOutput(result)\n }, 'GitVersion executed successfully')\n }\n\n private async command(): Promise {\n return this.safeExecute(async () => await this.tool.executeCommand(), 'GitVersion executed successfully')\n }\n\n private async processGitVersionOutput(result: ExecResult & { outputFile?: string }): Promise {\n this.buildAgent.debug('Processing GitVersion output')\n\n // Return error to be handled by calling function\n if (result.code !== 0) {\n return result\n }\n\n let gitVersionOutput: GitVersionOutput | null = null\n\n if (result.outputFile) {\n // Read from file\n this.buildAgent.debug(`Reading GitVersion variables from file: ${result.outputFile}`)\n try {\n gitVersionOutput = await this.tool.readGitVersionOutput(result.outputFile)\n } catch (error) {\n return this.handleOutputError(`Failed to read or parse GitVersion variables file: ${this.getErrorMessage(error)}`)\n }\n } else {\n // Fallback to parsing stdout (for backward compatibility)\n this.buildAgent.debug('Parsing GitVersion output from stdout')\n const stdout = result.stdout as string\n gitVersionOutput = this.extractGitVersionOutput(stdout)\n }\n\n if (gitVersionOutput === null) {\n return this.handleOutputError('GitVersion output is not valid JSON, see output details')\n }\n\n this.tool.writeGitVersionToAgent(gitVersionOutput)\n this.tool.updateBuildNumber()\n this.buildAgent.setSucceeded('GitVersion executed successfully', true)\n return result\n }\n\n private getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n }\n\n private handleOutputError(message: string): ExecResult {\n this.buildAgent.debug(message)\n this.buildAgent.setFailed(message, true)\n return {\n code: -1,\n error: new Error(message)\n }\n }\n\n /**\n * Attempts to extract and parse a JSON object representing `GitVersionOutput` from the given input string.\n * The method assumes the last closing curly brace (`}`) in the input belongs to the end of the JSON object,\n * and iteratively expands the search area backwards from each opening curly brace (`{`) until a valid JSON object is found.\n * If parsing fails, it logs debug information and continues searching until all possible start positions are exhausted.\n *\n * @param input - The string containing the potential JSON output from GitVersion.\n * @returns The parsed `GitVersionOutput` object if extraction and parsing succeed; otherwise, `null`.\n */\n private extractGitVersionOutput(input: string): GitVersionOutput | null {\n const allStartOfJsonIndexes = allIndexesOf(input, '{')\n // Assumed last '}' character will belong to the JSON object\n const endOfJsonIndex = input.lastIndexOf('}') + 1\n\n // Early return if no '{' or '}' found\n if (allStartOfJsonIndexes.length === 0) {\n this.buildAgent.debug(\"No opening curly brace '{' found in input; cannot extract JSON.\")\n return null\n }\n if (endOfJsonIndex === 0) {\n this.buildAgent.debug(\"No closing curly brace '}' found in input; cannot extract JSON.\")\n return null\n }\n\n // Start from the bottom when searching for the JSON object\n let startIndexArrayPos = allStartOfJsonIndexes.length - 1\n let decodePassCount = 1\n\n let currSearchString = input.substring(allStartOfJsonIndexes[startIndexArrayPos], endOfJsonIndex)\n let resultJson = null\n\n while (resultJson === null && startIndexArrayPos >= 0) {\n try {\n this.buildAgent.debug(`Starting JSON extraction at ${allStartOfJsonIndexes[startIndexArrayPos]} to ${endOfJsonIndex}`)\n\n resultJson = JSON.parse(currSearchString) as GitVersionOutput\n } catch (ex) {\n let exObject = new Error('Unable to parse exception object')\n\n if (ex instanceof Error) {\n exObject = ex\n }\n\n const errorMessage = `Failed to parse JSON object on pass ${decodePassCount}. Expanding search area from string index ${allStartOfJsonIndexes[startIndexArrayPos]} to ${endOfJsonIndex}. \\nPrevious search area:'${currSearchString}' \\nCaught Exception: ${exObject.message}`\n this.buildAgent.debug(errorMessage)\n\n // Expand search area\n decodePassCount++\n startIndexArrayPos--\n currSearchString = input.substring(allStartOfJsonIndexes[startIndexArrayPos], endOfJsonIndex)\n }\n }\n\n return resultJson\n }\n}\n"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/__tests__/tools/gitversion/tool.spec.ts b/src/__tests__/tools/gitversion/tool.spec.ts index 87ecf9163..e01b39456 100644 --- a/src/__tests__/tools/gitversion/tool.spec.ts +++ b/src/__tests__/tools/gitversion/tool.spec.ts @@ -1,4 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import * as fs from 'node:fs/promises' +import * as os from 'node:os' +import * as path from 'node:path' import { type IBuildAgent } from '@agents/common' import { type GitVersionOutput, type CommandSettings, type ExecuteSettings, GitVersionTool, IGitVersionSettingsProvider } from '@tools/gitversion' @@ -17,8 +20,8 @@ class TestGitVersionTool extends GitVersionTool { return super.getRepoDir(settings) } - async getExecuteArguments(workDir: string, options: ExecuteSettings): Promise { - return super.getExecuteArguments(workDir, options) + async getExecuteArguments(workDir: string, options: ExecuteSettings, outputFile?: string): Promise { + return super.getExecuteArguments(workDir, options, outputFile) } getCommandArguments(workDir: string, options: CommandSettings): string[] { @@ -265,6 +268,80 @@ describe('GitVersionTool', () => { } as ExecuteSettings) expect(args).toEqual(['workdir', '/output', 'json', '/l', 'console', '/updateprojectfiles']) }) + + it('should include outputfile argument when output file is provided', async () => { + const outputFile = '/tmp/gitversion-123.json' + const args = await tool.getExecuteArguments('workdir', {} as ExecuteSettings, outputFile) + expect(args).toEqual(['workdir', '/output', 'file', '/outputfile', outputFile, '/l', 'console']) + }) + + it('should not include outputfile argument when output file is not provided', async () => { + const args = await tool.getExecuteArguments('workdir', {} as ExecuteSettings) + expect(args).toEqual(['workdir', '/output', 'json', '/l', 'console']) + }) + + it('should include outputfile with other settings', async () => { + tool.init(true) + const outputFile = '/tmp/gitversion-123.json' + const args = await tool.getExecuteArguments( + 'workdir', + { + disableCache: true, + configFilePath: 'workdir/GitVersion.yml' + } as ExecuteSettings, + outputFile + ) + expect(args).toEqual(['workdir', '/output', 'file', '/outputfile', outputFile, '/l', 'console', '/nocache', '/config', 'workdir/GitVersion.yml']) + }) + }) + + describe('readGitVersionOutput', () => { + it('should read and parse JSON file correctly', async () => { + const outputFile = path.join(os.tmpdir(), 'test-gitversion-output.json') + const expectedOutput: Partial = { + Major: 1, + Minor: 2, + Patch: 3, + SemVer: '1.2.3' + } + + const buildAgent = {} as IBuildAgent + tool = new TestGitVersionTool(buildAgent) + + // Write test file + await fs.writeFile(outputFile, JSON.stringify(expectedOutput)) + + try { + const result = await tool.readGitVersionOutput(outputFile) + expect(result).toEqual(expectedOutput) + + // Verify file was deleted + const fileExists = await fs + .access(outputFile) + .then(() => true) + .catch(() => false) + expect(fileExists).toBe(false) + } finally { + // Cleanup in case test failed + await fs.unlink(outputFile).catch(() => {}) + } + }) + + it('should throw error for invalid JSON file', async () => { + const outputFile = path.join(os.tmpdir(), 'test-gitversion-invalid.json') + const buildAgent = {} as IBuildAgent + tool = new TestGitVersionTool(buildAgent) + + // Write invalid JSON + await fs.writeFile(outputFile, 'invalid json content') + + try { + await expect(tool.readGitVersionOutput(outputFile)).rejects.toThrow() + } finally { + // Cleanup + await fs.unlink(outputFile).catch(() => {}) + } + }) }) describe('getCommandArguments', () => { diff --git a/src/tools/gitversion/runner.ts b/src/tools/gitversion/runner.ts index 7a8f320fa..56a6704a1 100644 --- a/src/tools/gitversion/runner.ts +++ b/src/tools/gitversion/runner.ts @@ -33,7 +33,7 @@ export class Runner extends RunnerBase { private async execute(): Promise { return this.safeExecute(async () => { const result = await this.tool.executeJson() - return this.processGitVersionOutput(result) + return await this.processGitVersionOutput(result) }, 'GitVersion executed successfully') } @@ -41,25 +41,33 @@ export class Runner extends RunnerBase { return this.safeExecute(async () => await this.tool.executeCommand(), 'GitVersion executed successfully') } - private processGitVersionOutput(result: ExecResult): ExecResult { - this.buildAgent.debug('Parsing GitVersion output') + private async processGitVersionOutput(result: ExecResult & { outputFile?: string }): Promise { + this.buildAgent.debug('Processing GitVersion output') // Return error to be handled by calling function if (result.code !== 0) { return result } - const stdout = result.stdout as string - const gitVersionOutput = this.extractGitVersionOutput(stdout) + let gitVersionOutput: GitVersionOutput | null = null - if (gitVersionOutput === null) { - const errorMessage = 'GitVersion output is not valid JSON, see output details' - this.buildAgent.debug(errorMessage) - this.buildAgent.setFailed(errorMessage, true) - return { - code: -1, - error: new Error(errorMessage) + if (result.outputFile) { + // Read from file + this.buildAgent.debug(`Reading GitVersion variables from file: ${result.outputFile}`) + try { + gitVersionOutput = await this.tool.readGitVersionOutput(result.outputFile) + } catch (error) { + return this.handleOutputError(`Failed to read or parse GitVersion variables file: ${this.getErrorMessage(error)}`) } + } else { + // Fallback to parsing stdout (for backward compatibility) + this.buildAgent.debug('Parsing GitVersion output from stdout') + const stdout = result.stdout as string + gitVersionOutput = this.extractGitVersionOutput(stdout) + } + + if (gitVersionOutput === null) { + return this.handleOutputError('GitVersion output is not valid JSON, see output details') } this.tool.writeGitVersionToAgent(gitVersionOutput) @@ -68,6 +76,19 @@ export class Runner extends RunnerBase { return result } + private getErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error) + } + + private handleOutputError(message: string): ExecResult { + this.buildAgent.debug(message) + this.buildAgent.setFailed(message, true) + return { + code: -1, + error: new Error(message) + } + } + /** * Attempts to extract and parse a JSON object representing `GitVersionOutput` from the given input string. * The method assumes the last closing curly brace (`}`) in the input belongs to the end of the JSON object, diff --git a/src/tools/gitversion/tool.ts b/src/tools/gitversion/tool.ts index 892a1f9a6..899a9ca3f 100644 --- a/src/tools/gitversion/tool.ts +++ b/src/tools/gitversion/tool.ts @@ -1,3 +1,6 @@ +import * as path from 'node:path' +import * as fs from 'node:fs/promises' +import * as crypto from 'node:crypto' import { type ExecResult } from '@agents/common' import { ArgumentsBuilder, DotnetTool, keysOf } from '@tools/common' import { type CommandSettings, type ExecuteSettings, type GitVersionOutput } from './models' @@ -24,16 +27,19 @@ export class GitVersionTool extends DotnetTool { return new GitVersionSettingsProvider(this.buildAgent) } - async executeJson(): Promise { + async executeJson(): Promise { const settings = this.settingsProvider.getExecuteSettings() const workDir = await this.getRepoDir(settings) await this.checkShallowClone(settings, workDir) - const args = await this.getExecuteArguments(workDir, settings) + const outputFile = path.join(this.buildAgent.tempDir, `gitversion-${crypto.randomUUID()}.json`) + this.buildAgent.debug(`Writing GitVersion variables to file: ${outputFile}`) + const args = await this.getExecuteArguments(workDir, settings, outputFile) await this.setDotnetRoot() - return await this.executeTool(args) + const result = await this.executeTool(args) + return { ...result, outputFile } } async executeCommand(): Promise { @@ -80,8 +86,16 @@ export class GitVersionTool extends DotnetTool { return await super.getRepoPath(settings.targetPath) } - protected async getExecuteArguments(workDir: string, options: ExecuteSettings): Promise { - const builder = new ArgumentsBuilder().addArgument(workDir).addArgument('/output').addArgument('json').addArgument('/l').addArgument('console') + protected async getExecuteArguments(workDir: string, options: ExecuteSettings, outputFile?: string): Promise { + const builder = new ArgumentsBuilder().addArgument(workDir) + + if (outputFile) { + builder.addArgument('/output').addArgument('file').addArgument('/outputfile').addArgument(outputFile) + } else { + builder.addArgument('/output').addArgument('json') + } + + builder.addArgument('/l').addArgument('console') const { disableCache, @@ -160,6 +174,16 @@ export class GitVersionTool extends DotnetTool { } } + async readGitVersionOutput(outputFile: string): Promise { + const content = await fs.readFile(outputFile, 'utf8') + const output = JSON.parse(content) as GitVersionOutput + // Clean up the temporary file + await fs.unlink(outputFile).catch(() => { + // Ignore errors if file doesn't exist + }) + return output + } + private toCamelCase(input: string): string { return input.replace(/^\w|[A-Z]|\b\w|\s+/g, function (match, index) { if (+match === 0) return '' // or if (/\s+/.test(match)) for white spaces