Compare commits

..
Author SHA1 Message Date
Chet HuskandCopilot App ea1f75da7f Add info-level logging for MSBuild path, version, and architecture (#79)
Upgrades key diagnostics from core.debug to core.info so they are
visible by default (not just with ACTIONS_STEP_DEBUG), matching the
request in #79:
- Log the resolved MSBuild path
- Log the resolved MSBuild version (via MSBuild.exe -version -nologo,
  wrapped in try/catch so a failure to obtain it doesn't fail the action)
- Log the architecture used

Other existing debug logs are left unchanged. Rebuilt dist/ via
npm run build && npm run pack.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-21 16:19:59 -05:00
5 changed files with 37 additions and 153 deletions

No files matched your search

-30
View File
@@ -1,30 +0,0 @@
{
"problemMatcher": [
{
"owner": "msbuild",
"pattern": [
{
"regexp": "^\\s*(?:\\d+>\\s*)?([^\\s].*?)\\((\\d+)(?:,(\\d+))?(?:,\\d+)*\\)\\s*:\\s*(error|warning)\\s+([A-Za-z]+\\d+)\\s*:\\s*(.*?)(?:\\s+\\[(.+?)\\])?\\s*$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"code": 5,
"message": 6,
"fromPath": 7
}
]
},
{
"owner": "msbuild-no-location",
"pattern": [
{
"regexp": "^(?!.*\\().*\\b(error|warning)\\s+([A-Za-z]+\\d+)\\s*:\\s*(.*)$",
"severity": 1,
"code": 2,
"message": 3
}
]
}
]
}
-4
View File
@@ -69,10 +69,6 @@ This makes use of the vswhere tool which is a tool delivered by Microsoft to hel
vswhere-path: 'C:\path\to\your\tools\' vswhere-path: 'C:\path\to\your\tools\'
``` ```
## Problem matcher
This action registers a [problem matcher](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md) for MSBuild/csc-style `error`/`warning` output (for example `error MSB1234:` or `error CS1234:`). Once registered, matching lines in the build log are automatically surfaced as annotations in the GitHub Actions UI and, when applicable, as pull request check annotations.
## Notes on arguments ## Notes on arguments
While the Action enables you to specify a `vswhere` path as well as a `vs-version`, these are more advanced options and when using GitHub-hosted runners you should not need these and is recommended you don't specify them as they are optional. Using these require you to fully understand the runner environment, updates to the tools on the runner, and can cause failures if you are out of sync. For GitHub-hosted runners, omitting these arguments is the preferred usage. While the Action enables you to specify a `vswhere` path as well as a `vs-version`, these are more advanced options and when using GitHub-hosted runners you should not need these and is recommended you don't specify them as they are optional. Using these require you to fully understand the runner environment, updates to the tools on the runner, and can cause failures if you are out of sync. For GitHub-hosted runners, omitting these arguments is the preferred usage.
+18 -8
View File
@@ -42,16 +42,9 @@ if (VS_VERSION !== 'latest') {
VSWHERE_EXEC += `-version "${VS_VERSION}" `; VSWHERE_EXEC += `-version "${VS_VERSION}" `;
} }
core.debug(`Execution arguments: ${VSWHERE_EXEC}`); core.debug(`Execution arguments: ${VSWHERE_EXEC}`);
function registerProblemMatcher() {
const matcherPath = path.join(__dirname, '..', '.github', 'msbuild.json');
core.info(`##[add-matcher]${matcherPath}`);
}
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
// register the problem matcher so MSBuild/csc errors and warnings are
// annotated in the workflow log and any related pull request
registerProblemMatcher();
// exit if non Windows runner // exit if non Windows runner
if (IS_WINDOWS === false) { if (IS_WINDOWS === false) {
core.setFailed('setup-msbuild can only be run on Windows runners'); core.setFailed('setup-msbuild can only be run on Windows runners');
@@ -121,13 +114,30 @@ function run() {
core.setFailed('Unable to find MSBuild.'); core.setFailed('Unable to find MSBuild.');
return; return;
} }
core.info(`Found MSBuild tool path: ${foundToolPath}`);
core.info(`Using MSBuild architecture: ${MSBUILD_ARCH}`);
// try to get the MSBuild version for diagnostic purposes; a failure here shouldn't fail the action
try {
let msbuildVersion = '';
const versionOptions = {};
versionOptions.listeners = {
stdout: (data) => {
msbuildVersion += data.toString();
}
};
yield exec.exec(`"${foundToolPath}" -version -nologo`, [], versionOptions);
core.info(`Found MSBuild version: ${msbuildVersion.trim()}`);
}
catch (error) {
core.debug(`Unable to determine MSBuild version: ${error.message}`);
}
// extract the folder location for the tool // extract the folder location for the tool
const toolFolderPath = path.dirname(foundToolPath); const toolFolderPath = path.dirname(foundToolPath);
// set the outputs for the action to the folder path of msbuild // set the outputs for the action to the folder path of msbuild
core.setOutput('msbuildPath', toolFolderPath); core.setOutput('msbuildPath', toolFolderPath);
// add tool path to PATH // add tool path to PATH
core.addPath(toolFolderPath); core.addPath(toolFolderPath);
core.debug(`Tool path added to PATH: ${toolFolderPath}`); core.info(`Tool path added to PATH: ${toolFolderPath}`);
} }
catch (error) { catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
-101
View File
@@ -1,101 +0,0 @@
import * as fs from 'fs'
import * as path from 'path'
interface ProblemMatcherPattern {
regexp: string
file?: number
line?: number
column?: number
severity?: number
code?: number
message?: number
fromPath?: number
}
interface ProblemMatcherOwner {
owner: string
pattern: ProblemMatcherPattern[]
}
interface ProblemMatcherFile {
problemMatcher: ProblemMatcherOwner[]
}
const matcherPath = path.join(__dirname, '..', '..', '.github', 'msbuild.json')
const matcherFile: ProblemMatcherFile = JSON.parse(
fs.readFileSync(matcherPath, 'utf8')
)
function findOwner(owner: string): ProblemMatcherOwner {
const found = matcherFile.problemMatcher.find(m => m.owner === owner)
if (!found) {
throw new Error(`No matcher owner named ${owner} found`)
}
return found
}
describe('msbuild problem matcher', () => {
it('is valid JSON with the expected owners', () => {
expect(matcherFile.problemMatcher.map(m => m.owner)).toEqual([
'msbuild',
'msbuild-no-location'
])
})
describe('msbuild owner (file-based diagnostics)', () => {
const regexp = new RegExp(findOwner('msbuild').pattern[0].regexp)
it('matches a csc-style error with file, line, column and project path', () => {
const line =
'Program.cs(10,5): error CS1002: ; expected [C:\\proj\\proj.csproj]'
const match = regexp.exec(line)
expect(match).not.toBeNull()
expect(match?.[1]).toBe('Program.cs')
expect(match?.[2]).toBe('10')
expect(match?.[3]).toBe('5')
expect(match?.[4]).toBe('error')
expect(match?.[5]).toBe('CS1002')
expect(match?.[6]).toBe('; expected')
expect(match?.[7]).toBe('C:\\proj\\proj.csproj')
})
it('matches an MSB-coded warning with file and line only', () => {
const line =
'C:\\proj\\proj.csproj(15,1): warning MSB3277: Found conflicts [C:\\proj\\proj.csproj]'
const match = regexp.exec(line)
expect(match).not.toBeNull()
expect(match?.[4]).toBe('warning')
expect(match?.[5]).toBe('MSB3277')
})
it('matches a diagnostic without a trailing project path', () => {
const line = 'Program.cs(3,1): error CS0246: The type or namespace name could not be found'
const match = regexp.exec(line)
expect(match).not.toBeNull()
expect(match?.[5]).toBe('CS0246')
expect(match?.[6]).toBe(
'The type or namespace name could not be found'
)
expect(match?.[7]).toBeUndefined()
})
})
describe('msbuild-no-location owner (engine-level diagnostics)', () => {
const regexp = new RegExp(findOwner('msbuild-no-location').pattern[0].regexp)
it('matches an MSBuild engine error with no file/line info', () => {
const line = 'MSBUILD : error MSB1009: Project file does not exist.'
const match = regexp.exec(line)
expect(match).not.toBeNull()
expect(match?.[1]).toBe('error')
expect(match?.[2]).toBe('MSB1009')
expect(match?.[3]).toBe('Project file does not exist.')
})
it('does not match lines already covered by the file-based owner', () => {
const line =
'Program.cs(10,5): error CS1002: ; expected [C:\\proj\\proj.csproj]'
expect(regexp.test(line)).toBe(false)
})
})
})
+19 -10
View File
@@ -23,17 +23,8 @@ if (VS_VERSION !== 'latest') {
core.debug(`Execution arguments: ${VSWHERE_EXEC}`) core.debug(`Execution arguments: ${VSWHERE_EXEC}`)
function registerProblemMatcher(): void {
const matcherPath = path.join(__dirname, '..', '.github', 'msbuild.json')
core.info(`##[add-matcher]${matcherPath}`)
}
async function run(): Promise<void> { async function run(): Promise<void> {
try { try {
// register the problem matcher so MSBuild/csc errors and warnings are
// annotated in the workflow log and any related pull request
registerProblemMatcher()
// exit if non Windows runner // exit if non Windows runner
if (IS_WINDOWS === false) { if (IS_WINDOWS === false) {
core.setFailed('setup-msbuild can only be run on Windows runners') core.setFailed('setup-msbuild can only be run on Windows runners')
@@ -127,6 +118,24 @@ async function run(): Promise<void> {
return return
} }
core.info(`Found MSBuild tool path: ${foundToolPath}`)
core.info(`Using MSBuild architecture: ${MSBUILD_ARCH}`)
// try to get the MSBuild version for diagnostic purposes; a failure here shouldn't fail the action
try {
let msbuildVersion = ''
const versionOptions: ExecOptions = {}
versionOptions.listeners = {
stdout: (data: Buffer) => {
msbuildVersion += data.toString()
}
}
await exec.exec(`"${foundToolPath}" -version -nologo`, [], versionOptions)
core.info(`Found MSBuild version: ${msbuildVersion.trim()}`)
} catch (error) {
core.debug(`Unable to determine MSBuild version: ${error.message}`)
}
// extract the folder location for the tool // extract the folder location for the tool
const toolFolderPath = path.dirname(foundToolPath) const toolFolderPath = path.dirname(foundToolPath)
@@ -135,7 +144,7 @@ async function run(): Promise<void> {
// add tool path to PATH // add tool path to PATH
core.addPath(toolFolderPath) core.addPath(toolFolderPath)
core.debug(`Tool path added to PATH: ${toolFolderPath}`) core.info(`Tool path added to PATH: ${toolFolderPath}`)
} catch (error) { } catch (error) {
core.setFailed(error.message) core.setFailed(error.message)
} }