-
-
Notifications
You must be signed in to change notification settings - Fork 22
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
Fail the tool if any analysis fails #200
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ open Microsoft.CodeAnalysis.Sarif | |
open Microsoft.CodeAnalysis.Sarif.Writers | ||
open Microsoft.Extensions.Logging | ||
open Ionide.ProjInfo | ||
open FSharp.Analyzers.Cli | ||
open FSharp.Analyzers.Cli.CustomLogging | ||
|
||
type Arguments = | ||
|
@@ -136,6 +137,7 @@ let runProjectAux | |
(fsharpOptions: FSharpProjectOptions) | ||
(excludeIncludeFiles: Choice<Glob list, Glob list>) | ||
(mappings: SeverityMappings) | ||
: Async<Result<AnalyzerMessage list, AnalysisFailure> list> | ||
= | ||
async { | ||
let! checkProjectResults = fcs.ParseAndCheckProject(fsharpOptions) | ||
|
@@ -157,26 +159,33 @@ let runProjectAux | |
true | ||
| None -> false | ||
) | ||
|> Array.choose (fun fileName -> | ||
|> Array.map (fun fileName -> | ||
let fileContent = File.ReadAllText fileName | ||
let sourceText = SourceText.ofString fileContent | ||
|
||
Utils.typeCheckFile fcs logger fsharpOptions fileName (Utils.SourceOfSource.SourceText sourceText) | ||
|> Option.map (Utils.createContext checkProjectResults fileName sourceText) | ||
|> Result.map (Utils.createContext checkProjectResults fileName sourceText) | ||
) | ||
|> Array.map (fun ctx -> | ||
logger.LogInformation("Running analyzers for {0}", ctx.FileName) | ||
client.RunAnalyzers ctx | ||
match ctx with | ||
| Error e -> async.Return(Error e) | ||
| Ok ctx -> | ||
async { | ||
logger.LogInformation("Running analyzers for {0}", ctx.FileName) | ||
let! results = client.RunAnalyzers ctx | ||
return Ok results | ||
} | ||
) | ||
|> Async.Parallel | ||
|
||
return | ||
Some | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was never any chance that this was |
||
[ | ||
for messages in messagesPerAnalyzer do | ||
let mappedMessages = messages |> List.map (mapMessageToSeverity mappings) | ||
yield! mappedMessages | ||
] | ||
messagesPerAnalyzer | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Again, this could have been point-free.) |
||
|> Seq.map (fun messages -> | ||
match messages with | ||
| Error e -> Error e | ||
| Ok messages -> messages |> List.map (mapMessageToSeverity mappings) |> Ok | ||
) | ||
|> Seq.toList | ||
} | ||
|
||
let runProject | ||
|
@@ -267,7 +276,7 @@ let printMessages (msgs: AnalyzerMessage list) = | |
let msgLogger = factory.CreateLogger("") | ||
|
||
msgs | ||
|> Seq.iter (fun analyzerMessage -> | ||
|> List.iter (fun analyzerMessage -> | ||
let m = analyzerMessage.Message | ||
|
||
msgLogger.Log( | ||
|
@@ -284,7 +293,7 @@ let printMessages (msgs: AnalyzerMessage list) = | |
|
||
() | ||
|
||
let writeReport (results: AnalyzerMessage list option) (codeRoot: string option) (report: string) = | ||
let writeReport (results: AnalyzerMessage list) (codeRoot: string option) (report: string) = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was never actually optional; we always statically knew that this |
||
try | ||
let codeRoot = | ||
match codeRoot with | ||
|
@@ -319,7 +328,7 @@ let writeReport (results: AnalyzerMessage list option) (codeRoot: string option) | |
|
||
sarifLogger.AnalysisStarted() | ||
|
||
for analyzerResult in (Option.defaultValue List.empty results) do | ||
for analyzerResult in results do | ||
let reportDescriptor = ReportingDescriptor() | ||
reportDescriptor.Id <- analyzerResult.Message.Code | ||
reportDescriptor.Name <- analyzerResult.Message.Message | ||
|
@@ -375,20 +384,6 @@ let writeReport (results: AnalyzerMessage list option) (codeRoot: string option) | |
logger.LogError(ex, "Could not write sarif to {report}", report) | ||
logger.LogInformation("{0}", ex) | ||
|
||
let calculateExitCode (msgs: AnalyzerMessage list option) : int = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now extracted to the bottom of the file, where the logic is inlined. That's because our exit code now depends on knowledge we only have down there, and I didn't really fancy passing more args into this function. |
||
match msgs with | ||
| None -> -1 | ||
| Some msgs -> | ||
let check = | ||
msgs | ||
|> List.exists (fun analyzerMessage -> | ||
let message = analyzerMessage.Message | ||
|
||
message.Severity = Severity.Error | ||
) | ||
|
||
if check then -2 else 0 | ||
|
||
/// If multiple MSBuild properties are given in one -p flag like -p:prop1="val1a;val1b;val1c";prop2="1;2;3";prop3=val3 | ||
/// argu will think it means prop1 has the value: "val1a;val1b;val1c";prop2="1;2;3";prop3=val3 | ||
/// so this function expands the value into multiple key-value properties | ||
|
@@ -623,6 +618,7 @@ let main argv = | |
| [], Some fscArgs -> | ||
runFscArgs client fscArgs exclInclFiles severityMapping | ||
|> Async.RunSynchronously | ||
|> Some | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Fallout from the "remove the spurious option type" in FSharp.Analyzers.SDK.fs) |
||
| projects, None -> | ||
for projPath in projects do | ||
if not (File.Exists(projPath)) then | ||
|
@@ -635,19 +631,39 @@ let main argv = | |
) | ||
|> Async.Sequential | ||
|> Async.RunSynchronously | ||
|> Array.choose id | ||
|> List.concat | ||
|> Some | ||
|
||
results |> Option.iter printMessages | ||
report |> Option.iter (writeReport results codeRoot) | ||
match results with | ||
| None -> -1 | ||
| Some results -> | ||
let results, hasError = | ||
match Result.allOkOrError results with | ||
| Ok results -> results, false | ||
| Error(results, _errors) -> results, true | ||
|
||
let results = results |> List.concat | ||
|
||
if failedAssemblies > 0 then | ||
logger.LogError( | ||
"Because we failed to load some assemblies to obtain analyzers from them, exiting (failure count: {FailedAssemblyLoadCount})", | ||
failedAssemblies | ||
) | ||
printMessages results | ||
|
||
report |> Option.iter (writeReport results codeRoot) | ||
|
||
let check = | ||
results | ||
|> List.exists (fun analyzerMessage -> | ||
let message = analyzerMessage.Message | ||
|
||
message.Severity = Severity.Error | ||
) | ||
|
||
if failedAssemblies > 0 then | ||
logger.LogError( | ||
"Because we failed to load some assemblies to obtain analyzers from them, exiting (failure count: {FailedAssemblyLoadCount})", | ||
failedAssemblies | ||
) | ||
|
||
exit -3 | ||
exit -3 | ||
|
||
calculateExitCode results | ||
if check then -2 | ||
elif hasError then -4 | ||
else 0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module FSharp.Analyzers.Cli.Result | ||
|
||
let allOkOrError<'ok, 'err> (results: Result<'ok, 'err> list) : Result<'ok list, 'ok list * 'err list> = | ||
let oks, errs = | ||
(([], []), results) | ||
||> List.fold (fun (oks, errs) result -> | ||
match result with | ||
| Ok ok -> ok :: oks, errs | ||
| Error err -> oks, err :: errs | ||
) | ||
|
||
let oks = List.rev oks | ||
let errs = List.rev errs | ||
|
||
if List.isEmpty errs then Ok oks else Error(oks, errs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could all have been done point-free but I thought it was clearer this way.