-
Notifications
You must be signed in to change notification settings - Fork 753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export lint output to file #11960
Comments
@johnnyreilly I believe SARIF was picked as a base format that can be converted. As a stopgap, have you tried converting from sarif -> junit xml format? For example: ~/.azure/bin/bicep lint main.bicep --diagnostics-format sarif 2> lint.sarif
npx -y sarif-junit -i lint.sarif -o lint.xml Gives me: <?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="My suite" tests="8" failures="0" errors="0" skipped="0">
<testcase classname="artifacts-parameters" name="If an '_artifactsLocation' parameter is provided, an '_artifactsLocationSasToken' parameter must also be provided. [https://aka.ms/bicep/linter/artifacts-parameters]" file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="no-loc-expr-outside-params" name="Use a parameter here instead of 'resourceGroup().location'. 'resourceGroup().location' and 'deployment().location' should only be used as a default value for parameters. [https://aka.ms/bicep/linter/no-loc-expr-outside-params]" file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="simplify-interpolation" name="Remove unnecessary string interpolation. [https://aka.ms/bicep/linter/simplify-interpolation]" file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="no-loc-expr-outside-params" name="Use a parameter here instead of 'resourceGroup().location'. 'resourceGroup().location' and 'deployment().location' should only be used as a default value for parameters. [https://aka.ms/bicep/linter/no-loc-expr-outside-params]" file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="BCP036" name="The property "logProgress" expected a value of type "bool | null" but the provided value is of type "'false'". If this is an inaccuracy in the documentation, please report it to the Bicep Team. [https://aka.ms/bicep-type-issues]" file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="BCP036" name="The property "logVerbose" expected a value of type "bool | null" but the provided value is of type "'false'". If this is an inaccuracy in the documentation, please report it to the Bicep Team. [https://aka.ms/bicep-type-issues]" file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="BCP081" name="Resource type "Microsoft.Automation/automationAccounts/webhooks@2018-06-30" does not have types available." file="//Users/ant/Desktop/main.bicep"/>
<testcase classname="simplify-interpolation" name="Remove unnecessary string interpolation. [https://aka.ms/bicep/linter/simplify-interpolation]" file="//Users/ant/Desktop/main.bicep"/>
</testsuite>
</testsuites> |
oh nice! let me try! What do you think about the file output option? I'm doing this right now:
|
I think that's a great suggestion - redirecting stderr has pitfalls as it's not straightforward to distinguish between success (sarif format output) and failure (for example, failing to find the .bicep file on disk). |
BTW I'm using In the interim I'm planning to build a mini parser which will read the build output - I can throw it away in future once lint lands. |
Built a mini //@ts-check
const fs = require("fs");
// This is necessary until direct lint support lands in the Azure CLI for Bicep
// See: https://github.com/Azure/bicep/issues/11960
/**
* @typedef {Object} BicepLintWarningsOrError
* @property {string} type
* @property {string} typeAndMessage
* @property {string} filePath
* @property {string} lineNumber
* @property {string} columnNumber
* @property {string} line
*/
async function convertBicepOutputToJUnit() {
// Check if there is at least two command-line arguments
if (process.argv.length < 4) {
console.error(
"Example usage: node scripts/bicep-lint-to-junit.js containerapps.bicep.lint-output.txt containerapps.bicep.lint-output.junit.xml"
);
process.exit(1); // Exit with an error code
}
// Get the first command-line argument (index 2 because 0 and 1 are reserved for node and script file paths)
const bicepOutputPath = process.argv[2];
const bicepOutputJUnitPath = process.argv[3];
const dirname = process.cwd();
console.log("Loading:", bicepOutputPath, "from:", dirname);
const bicepOutput = await fs.promises.readFile(bicepOutputPath, "utf-8");
const bicepOutputLines = bicepOutput
.replace(/\r/g, "")
.split("\n")
.filter((line) => line.trim().length > 0)
.map((line) =>
line
.replace("WARNING: ", "")
.replace("ERROR: ", "")
.replace(dirname, "")
.replace(/"/g, "")
);
if (bicepOutputLines.length === 0) {
console.log("No issues found in:", bicepOutputPath);
return;
}
/** @type {Map<string, BicepLintWarningsOrError[]>} */
const bicepLintWarningsAndErrors = bicepOutputLines
.map((line) => {
try {
const [filePathAndLine, typeAndMessage] = line.split(" : ");
const [filePath, lineParts] = filePathAndLine.split("(");
const [lineNumber, columnNumber] = lineParts
?.replace(")", "")
.split(",");
const type = typeAndMessage.startsWith("Error")
? "Error"
: typeAndMessage.startsWith("Warning")
? "Warning"
: "Unknown";
return {
type,
typeAndMessage,
filePath,
lineNumber,
columnNumber,
line,
};
} catch (error) {
console.error("Error parsing line:", line);
console.error(error);
return undefined;
}
})
.reduce(
(groupedByFilePath, curr) =>
curr === undefined
? groupedByFilePath
: groupedByFilePath.set(curr.filePath, [...(groupedByFilePath.get(curr.filePath) || []), curr]),
new Map()
);
if (bicepLintWarningsAndErrors.size === 0) {
console.log("No issues parsed in:", bicepOutputPath);
return;
}
console.log("Parsed issues:", Array.from(bicepLintWarningsAndErrors.values()).flat());
const entries = Array.from(bicepLintWarningsAndErrors.entries());
const junit = `<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
${entries.map(([filePath, bicepLintWarningsAndErrors]) => {
return ` <testsuite name="${filePath}">
${bicepLintWarningsAndErrors
.map((lintOrError) => lintOrError.type === "Error"
? ` <testcase name="${lintOrError.line.replace(filePath, "")}" classname="${filePath}" file="${lintOrError.filePath}" line="${lintOrError.lineNumber}">
<failure message="${lintOrError.typeAndMessage}" />
</testcase>`
: ` <testcase name="${lintOrError.line.replace(filePath, "")}" classname="${filePath}" file="${lintOrError.filePath}" line="${lintOrError.lineNumber}" />`
)
.join("\n")}
</testsuite>
`
}).join("\n")}
</testsuites>`;
console.log(`
JUnit output:
${junit}`);
console.log("Saving:", bicepOutputJUnitPath);
await fs.promises.writeFile(bicepOutputJUnitPath, junit);
console.log("Done!");
}
convertBicepOutputToJUnit().catch((error) => {
console.error(error);
process.exit(1);
});
// node scripts/bicep-lint-to-junit.js containerapps.bicep.lint-output.txt containerapps.bicep.lint-output.txt.junit.xml |
Parking the junit conversation for a moment @anthony-c-martin, I've been having a quick gander at what an implementation might look like for a potential By the looks of it, the relevant code sits in https://github.com/Azure/bicep/blob/main/src/Bicep.Cli/Logging/BicepDiagnosticLogger.cs A simple implementation could take this code: bicep/src/Bicep.Cli/Logging/BicepDiagnosticLogger.cs Lines 130 to 132 in d7b6beb
which turns the SARIF output into JSON and flushes it to the log, and also (if an Is something like that what you had in mind? Or something different? Of course with the current implementation that would only work if you had SARIF format selected; so that would have to change. But I wanted to get a sense of whether that would be the sort of thing you felt worked? Also to add, I'm imagining that outputting to file will not replace outputting to console; it will be additional. So if What do you think? |
Sorry for the long delay in responding!
Yeah, I believe this would work. However I'm wondering if we need it - instead could we just output to stdout instead of stderr? That way you'd be able to just to run:
My opinion is that it would give more flexibility to just log to file if the bicep lint main.bicep --diagnostics-format sarif > lint.sarif
cat lint.sarif |
* Makes `bicep lint` command simpler to use with sarif + output redirection (described in #11960) * Simplify the diagnostic logging logic to avoid the need to 'setup' and 'flush' the logger. ###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/12703)
I will respond to this soon - promise! |
FWIW here's how I've set this up with the latest Bicep release (0.24.24): Example PR with warnings/errors raised by the linter: |
This looks quite promising! Let me give it a try on ADO pipelines |
Just doing some experimentation now @anthony-c-martin. I'm not sure whether this should be regarded as a bug or something that makes the case for a dedicated output to process mechanism. Consider a {
// See https://aka.ms/bicep/config for more information on Bicep configuration options
// Press CTRL+SPACE/CMD+SPACE at any location to see Intellisense suggestions
"analyzers": {
"core": {
"rules": {
"no-unused-params": {
"level": "warning"
},
"no-unused-vars": {
"level": "warning"
},
"secure-secrets-in-params": {
"level": "error"
}
}
}
},
"experimentalFeaturesEnabled": {
"sourceMapping": true
}
} Running
The presence of What would the advice be on how to handle this? As I said at the top, I'm not sure whether this should be regarded as a bug or something that makes the case for a dedicated output to process mechanism. What do you reckon? If I turn off experimental features, this issue goes away. But generally there's probably a need to handle this in a way that affords consistent output? |
Additional thoughts: I took a look at the linting in GitHub Actions here: https://github.com/anthony-c-martin/bicep-on-k8s/actions/runs/7224883231/job/19687151956?pr=1 By the looks of it, in the case of an error you just get a hard fail with no output. The pull request: anthony-c-martin/bicep-on-k8s#1 initially got me very excited, as I thought it was the lint failures being surfaced into the PR. Unless I'm reading it wrong, it seems like the messages in the PR like this: are actually coming from somewhere else. Certainly if I fail a lint with an error using Bicep 0.24.24, the
Given you'll generally get the full error later when a bicep build takes place, it's still relatively straightforward to get to the reason for a build failure. It does feel unfortunate that lint fails without revealing too much though. |
@johnnyreilly the difference is that I'm using the Here's what the relevant part of my CI pipeline looks like:
The lint issues are indeed being surfaced into the PR! |
The problem here is the stderr redirect - as of version The fix I made was to solve exactly this problem - giving the caller a way to accurately read sarif output whilst being able to accurately differentiate it from errors. |
Yup - I'm travelling right now, but I'll try and do this when I get to my destination. I'll link back to this and @ you
You're saying the code scanning messages on the PR come from the bicep task? And that if the Azure CLI didn't have a bug, I could expect similar behaviour? |
Yes, exactly. The |
That is cool! |
I realised that in the other discussion we missed the potential other bug @anthony-c-martin. I'm not sure whether this should be regarded as a bug or something that makes the case for a dedicated output to process mechanism. Consider a {
// See https://aka.ms/bicep/config for more information on Bicep configuration options
// Press CTRL+SPACE/CMD+SPACE at any location to see Intellisense suggestions
"analyzers": {
"core": {
"rules": {
"no-unused-params": {
"level": "warning"
},
"no-unused-vars": {
"level": "warning"
},
"secure-secrets-in-params": {
"level": "error"
}
}
}
},
"experimentalFeaturesEnabled": {
"sourceMapping": true
}
} Running
The presence of What would the advice be on how to handle this? As I said at the top, I'm not sure whether this should be regarded as a bug or something that makes the case for a dedicated output to process mechanism. What do you reckon? If I turn off experimental features, this issue goes away. But generally there's probably a need to handle this in a way that affords consistent output? I'm guessing this is unrelated to the |
Take a look at this comment to resolve the issue you're describing. This should work with Bicep CLI, and should be unrelated to the AzCLI bug. |
Okay cool, so I think we go from:
to:
Will experiment |
Looks good! |
hey @anthony-c-martin! I'm back from travelling now and just catching up on this. I think there's a few separate things happening in this discussion and I realise from reading it back it's a little confusing. Herefollows an attempt by me to disambiguate the different topics under discussion. Bug in Azure CLI around surfacing output when exit code is non-0From here: #11960 (comment) You asked if I could raise an issue with the Azure CLI project. Raised here: Azure/azure-cli#28259 Exporting lint output to fileYou've outlined that it's possible to output lints to a file using
This works. But there are gotchas. Consider the following from a GitHub Action: - name: Lint Bicep
uses: azure/CLI@v1
with:
inlineScript: |
az bicep lint --file ./infra/main.bicep --diagnostics-format sarif > bicep.sarif Ideally this would run and output lints to The contents of
So because Bicep wasn't initially installed on the GitHub Actions server, the bicep lint output was prefixed by:
Which means that the subsequent upload task fails like this: It's possible to work around this initial issue by say running - name: Lint Bicep
uses: azure/CLI@v1
with:
inlineScript: |
az bicep version
az bicep lint --file ./infra/main.bicep --diagnostics-format sarif > bicep.sarif But, whilst this works around the particular "bicep was not installed" issue that surfaced in this case, it doesn't solve the "there is other output coming from Maybe that's okay; maybe it's fine to tackle each other issue that might present in the same way as it comes. My own instinct is that the redirect to file output approach isn't as reliable as I'd like for this reason. But maybe you feel it's good enough? What do you think? |
I think this is another AzCLI bug - Bicep is very strict about only writing the SARIF output to stdout for this exact reason. It looks like there's actually a PR open to fix this: Azure/azure-cli#28188. |
okay cool - fingers crossed it lands! |
Is your feature request related to a problem? Please describe.
It's very exciting to see linting become a first class citizen of Bicep with @johan-lindqvist's work on #10819
My understanding of this feature (which I hope to be able to use when it ships with the Azure CLI Azure/azure-cli#27378) is that it outputs errors and warnings to stdout, in two possible formats; the default one and Sarif.
Whilst this is great, it means there's a job of parsing work to do if you'd like to interrogate the results, perhaps to surface them in an Azure Pipeline. We tackle this with arm-ttk at the moment with this extension by @sam-cogan: https://github.com/sam-cogan/arm-ttk-extension-xplatform
Describe the solution you'd like
The idea I have in mind, is the ability to output
lint
results to a file. And possibly expand the formats available to include say JUnit. You can kind of see the scenarion that I have in mind in this blogpost that demos surfacing test results from Vitest (could be anything really) in Azure PipelinesWhat do you think?
I can see the lint options currently look like this:
Imagine an extra
--outfile
option as well, which if supplied passes the text output into that file?The text was updated successfully, but these errors were encountered: