11using Semmle . Extraction . CSharp ;
22using Semmle . Util . Logging ;
33using Semmle . Autobuild . Shared ;
4- using Semmle . Util ;
5- using System . Linq ;
64
75namespace Semmle . Autobuild . CSharp
86{
@@ -31,16 +29,25 @@ public CSharpAutobuildOptions(IBuildActions actions) : base(actions)
3129
3230 public class CSharpAutobuilder : Autobuilder < CSharpAutobuildOptions >
3331 {
34- private const string buildCommandDocsUrl =
35- "https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages" ;
36-
37- private readonly AutoBuildRule autoBuildRule ;
38-
39- public CSharpAutobuilder ( IBuildActions actions , CSharpAutobuildOptions options ) : base ( actions , options , new CSharpDiagnosticClassifier ( ) ) =>
40- this . autoBuildRule = new AutoBuildRule ( this ) ;
32+ public CSharpAutobuilder ( IBuildActions actions , CSharpAutobuildOptions options ) : base ( actions , options ) { }
4133
4234 public override BuildScript GetBuildScript ( )
4335 {
36+ /// <summary>
37+ /// A script that checks that the C# extractor has been executed.
38+ /// </summary>
39+ BuildScript CheckExtractorRun ( bool warnOnFailure ) =>
40+ BuildScript . Create ( actions =>
41+ {
42+ if ( actions . FileExists ( Extractor . GetCSharpLogPath ( ) ) )
43+ return 0 ;
44+
45+ if ( warnOnFailure )
46+ Log ( Severity . Error , "No C# code detected during build." ) ;
47+
48+ return 1 ;
49+ } ) ;
50+
4451 var attempt = BuildScript . Failure ;
4552 switch ( GetCSharpBuildStrategy ( ) )
4653 {
@@ -58,9 +65,47 @@ public override BuildScript GetBuildScript()
5865 attempt = new DotNetRule ( ) . Analyse ( this , false ) & CheckExtractorRun ( true ) ;
5966 break ;
6067 case CSharpBuildStrategy . Auto :
68+ var cleanTrapFolder =
69+ BuildScript . DeleteDirectory ( TrapDir ) ;
70+ var cleanSourceArchive =
71+ BuildScript . DeleteDirectory ( SourceArchiveDir ) ;
72+ var tryCleanExtractorArgsLogs =
73+ BuildScript . Create ( actions =>
74+ {
75+ foreach ( var file in Extractor . GetCSharpArgsLogs ( ) )
76+ {
77+ try
78+ {
79+ actions . FileDelete ( file ) ;
80+ }
81+ catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block]
82+ { }
83+ }
84+
85+ return 0 ;
86+ } ) ;
87+ var attemptExtractorCleanup =
88+ BuildScript . Try ( cleanTrapFolder ) &
89+ BuildScript . Try ( cleanSourceArchive ) &
90+ tryCleanExtractorArgsLogs &
91+ BuildScript . DeleteFile ( Extractor . GetCSharpLogPath ( ) ) ;
92+
93+ /// <summary>
94+ /// Execute script `s` and check that the C# extractor has been executed.
95+ /// If either fails, attempt to cleanup any artifacts produced by the extractor,
96+ /// and exit with code 1, in order to proceed to the next attempt.
97+ /// </summary>
98+ BuildScript IntermediateAttempt ( BuildScript s ) =>
99+ ( s & CheckExtractorRun ( false ) ) |
100+ ( attemptExtractorCleanup & BuildScript . Failure ) ;
101+
61102 attempt =
62- // Attempt a few different build strategies to see if one works
63- this . autoBuildRule . Analyse ( this , true ) |
103+ // First try .NET Core
104+ IntermediateAttempt ( new DotNetRule ( ) . Analyse ( this , true ) ) |
105+ // Then MSBuild
106+ ( ( ) => IntermediateAttempt ( new MsBuildRule ( ) . Analyse ( this , true ) ) ) |
107+ // And finally look for a script that might be a build script
108+ ( ( ) => new BuildCommandAutoRule ( DotNetRule . WithDotNet ) . Analyse ( this , true ) & CheckExtractorRun ( true ) ) |
64109 // All attempts failed: print message
65110 AutobuildFailure ( ) ;
66111 break ;
@@ -69,127 +114,6 @@ public override BuildScript GetBuildScript()
69114 return attempt ;
70115 }
71116
72- /// <summary>
73- /// A script that checks that the C# extractor has been executed.
74- /// </summary>
75- public BuildScript CheckExtractorRun ( bool warnOnFailure ) =>
76- BuildScript . Create ( actions =>
77- {
78- if ( actions . FileExists ( Extractor . GetCSharpLogPath ( ) ) )
79- return 0 ;
80-
81- if ( warnOnFailure )
82- Log ( Severity . Error , "No C# code detected during build." ) ;
83-
84- return 1 ;
85- } ) ;
86-
87- protected override void AutobuildFailureDiagnostic ( )
88- {
89- // if `ScriptPath` is not null here, the `BuildCommandAuto` rule was
90- // run and found at least one script to execute
91- if ( this . autoBuildRule . BuildCommandAutoRule . ScriptPath is not null )
92- {
93- var relScriptPath = this . MakeRelative ( autoBuildRule . BuildCommandAutoRule . ScriptPath ) ;
94-
95- // if we found multiple build scripts in the project directory, then we can say
96- // as much to indicate that we may have picked the wrong one;
97- // otherwise, we just report that the one script we found didn't work
98- DiagnosticMessage message =
99- this . autoBuildRule . BuildCommandAutoRule . CandidatePaths . Count ( ) > 1 ?
100- new (
101- this . Options . Language ,
102- "multiple-build-scripts" ,
103- "There are multiple potential build scripts" ,
104- markdownMessage :
105- "CodeQL found multiple potential build scripts for your project and " +
106- $ "attempted to run `{ relScriptPath } `, which failed. " +
107- "This may not be the right build script for your project. " +
108- $ "Set up a [manual build command]({ buildCommandDocsUrl } )."
109- ) :
110- new (
111- this . Options . Language ,
112- "script-failure" ,
113- "Unable to build project using build script" ,
114- markdownMessage :
115- "CodeQL attempted to build your project using a script located at " +
116- $ "`{ relScriptPath } `, which failed. " +
117- $ "Set up a [manual build command]({ buildCommandDocsUrl } )."
118- ) ;
119-
120- AddDiagnostic ( message ) ;
121- }
122-
123- // project files which don't exist get marked as not .NET core projects, but we don't want
124- // to show an error for this if the files don't exist
125- var foundNotDotNetProjects = autoBuildRule . DotNetRule . NotDotNetProjects . Where (
126- proj => this . Actions . FileExists ( proj . FullPath )
127- ) ;
128-
129- // both dotnet and msbuild builds require project or solution files; if we haven't found any
130- // then neither of those rules would've worked
131- if ( this . ProjectsOrSolutionsToBuild . Count == 0 )
132- {
133- this . AddDiagnostic ( new (
134- this . Options . Language ,
135- "no-projects-or-solutions" ,
136- "No project or solutions files found" ,
137- markdownMessage :
138- "CodeQL could not find any project or solution files in your repository. " +
139- $ "Set up a [manual build command]({ buildCommandDocsUrl } )."
140- ) ) ;
141- }
142- // show a warning if there are projects which are not compatible with .NET Core, in case that is unintentional
143- else if ( foundNotDotNetProjects . Any ( ) )
144- {
145- this . AddDiagnostic ( new (
146- this . Options . Language ,
147- "dotnet-incompatible-projects" ,
148- "Some projects are incompatible with .NET Core" ,
149- severity : DiagnosticMessage . TspSeverity . Warning ,
150- markdownMessage : $ """
151- CodeQL found some projects which cannot be built with .NET Core:
152-
153- { autoBuildRule . DotNetRule . NotDotNetProjects . Select ( p => this . MakeRelative ( p . FullPath ) ) . ToMarkdownList ( MarkdownUtil . CodeFormatter , 5 ) }
154- """
155- ) ) ;
156- }
157-
158- // report any projects that failed to build with .NET Core
159- if ( autoBuildRule . DotNetRule . FailedProjectsOrSolutions . Any ( ) )
160- {
161- this . AddDiagnostic ( new (
162- this . Options . Language ,
163- "dotnet-build-failure" ,
164- "Some projects or solutions failed to build using .NET Core" ,
165- markdownMessage : $ """
166- CodeQL was unable to build the following projects using .NET Core:
167-
168- { autoBuildRule . DotNetRule . FailedProjectsOrSolutions . Select ( p => this . MakeRelative ( p . FullPath ) ) . ToMarkdownList ( MarkdownUtil . CodeFormatter , 10 ) }
169-
170- Set up a [manual build command]({ buildCommandDocsUrl } ).
171- """
172- ) ) ;
173- }
174-
175- // report any projects that failed to build with MSBuild
176- if ( autoBuildRule . MsBuildRule . FailedProjectsOrSolutions . Any ( ) )
177- {
178- this . AddDiagnostic ( new (
179- this . Options . Language ,
180- "msbuild-build-failure" ,
181- "Some projects or solutions failed to build using MSBuild" ,
182- markdownMessage : $ """
183- CodeQL was unable to build the following projects using MSBuild:
184-
185- { autoBuildRule . MsBuildRule . FailedProjectsOrSolutions . Select ( p => this . MakeRelative ( p . FullPath ) ) . ToMarkdownList ( MarkdownUtil . CodeFormatter , 10 ) }
186-
187- Set up a [manual build command]({ buildCommandDocsUrl } ).
188- """
189- ) ) ;
190- }
191- }
192-
193117 /// <summary>
194118 /// Gets the build strategy that the autobuilder should apply, based on the
195119 /// options in the `lgtm.yml` file.
0 commit comments