17
17
package fr .cnes .sonar .plugins .scan .tasks ;
18
18
19
19
import fr .cnes .sonar .plugins .scan .utils .StringManager ;
20
+
20
21
import org .sonar .api .config .Configuration ;
21
22
import org .sonar .api .server .ws .Request ;
22
23
import org .sonar .api .server .ws .Response ;
23
24
import org .sonar .api .utils .text .JsonWriter ;
24
25
26
+ import com .google .gson .Gson ;
27
+ import com .google .gson .reflect .TypeToken ;
28
+
25
29
import java .io .File ;
26
30
import java .io .FileWriter ;
27
31
import java .io .IOException ;
32
+ import java .lang .reflect .Type ;
28
33
import java .nio .file .Files ;
29
34
import java .nio .file .Paths ;
30
35
import java .text .SimpleDateFormat ;
36
+ import java .util .ArrayList ;
31
37
import java .util .Date ;
38
+ import java .util .List ;
32
39
import java .util .concurrent .*;
33
40
34
41
/**
35
42
* Execute the scan of a project
43
+ *
36
44
* @author lequal
37
45
*/
38
46
public class AnalysisTask extends AbstractTask {
39
47
40
48
private final Configuration config ;
41
49
42
- public AnalysisTask (Configuration config ){
50
+ public AnalysisTask (Configuration config ) {
43
51
this .config = config ;
44
52
}
53
+
45
54
/**
46
55
* Logged message when a file can not be deleted
47
56
*/
48
- private static final String FILE_DELETION_ERROR =
49
- "The following file could not be deleted: %s." ;
57
+ private static final String FILE_DELETION_ERROR = "The following file could not be deleted: %s." ;
50
58
/**
51
59
* Logged message when a file can not be set as executable
52
60
*/
53
- private static final String FILE_PERMISSIONS_ERROR =
54
- "Permissions of the following file could not be changed: %s." ;
61
+ private static final String FILE_PERMISSIONS_ERROR = "Permissions of the following file could not be changed: %s." ;
55
62
/**
56
63
* Just a slash
57
64
*/
@@ -69,55 +76,67 @@ public AnalysisTask(Configuration config){
69
76
*/
70
77
private static final String NEW_LINE = "\n " ;
71
78
72
-
73
-
74
79
/**
75
80
* Execute the scan of a project
76
- * @param projectName name of the project to analyze
77
- * @param projectFolder url of the folder containing the project to analyze
81
+ *
82
+ * @param projectName name of the project to analyze
83
+ * @param projectFolder url of the folder containing the project to
84
+ * analyze
78
85
* @param sonarProjectProperties the sonar-project.properties as string
86
+ * @param qualityProfiles the quality profiles as string
79
87
* @return logs
80
- * @throws IOException when a file writing goes wrong
88
+ * @throws IOException when a file writing goes wrong
81
89
* @throws InterruptedException when a command is not finished
82
90
*/
83
- private String analyze (final String projectName , final String projectFolder , final String sonarProjectProperties )
91
+ private String analyze (final String projectName , final String projectFolder , final String sonarProjectProperties ,
92
+ final String qualityProfiles )
84
93
throws IOException , InterruptedException {
85
94
// setting a timer based on user's timeout property configuration
86
- final Integer timeout = Integer .parseInt (config .get (StringManager .string (StringManager .TIMEOUT_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )));
95
+ final Integer timeout = Integer .parseInt (config .get (StringManager .string (StringManager .TIMEOUT_PROP_DEF_KEY ))
96
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )));
87
97
final ExecutorService service = Executors .newSingleThreadExecutor ();
88
98
try {
89
99
final Runnable task = () -> {
90
100
try {
91
101
// path where spp should be written
92
102
final String sppPath = String .format (StringManager .string (StringManager .CNES_SPP_PATH ),
93
- config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )), projectFolder );
103
+ config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
104
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )),
105
+ projectFolder );
94
106
95
107
// write sonar-project.properties in the project folder
96
108
writeTextFile (sppPath , sonarProjectProperties );
97
109
// build the scan command
98
110
final String analysisCommand = String .format (
99
111
StringManager .string (StringManager .CNES_COMMAND_SCAN ),
100
- config .get (StringManager .string (StringManager .SCANNER_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )),
101
- config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )),
112
+ config .get (StringManager .string (StringManager .SCANNER_PROP_DEF_KEY ))
113
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )),
114
+ config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
115
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )),
102
116
projectFolder ,
103
- config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )),
117
+ config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
118
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )),
104
119
projectFolder );
105
- final File script = createScript (projectFolder , analysisCommand );
120
+ final File script = createScript (projectFolder , analysisCommand , qualityProfiles );
106
121
107
122
// string formatted date as string
108
123
final String date = new SimpleDateFormat (
109
124
StringManager .string (StringManager .DATE_PATTERN )).format (new Date ());
110
125
111
126
// export log file
112
127
final String logPath = String .format (StringManager .string (StringManager .CNES_LOG_PATH ),
113
- config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )), date , projectName );
128
+ config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
129
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )),
130
+ date , projectName );
114
131
115
132
// scan execution
116
- final String scriptCommand = config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )) +
133
+ final String scriptCommand = config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
134
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )) +
117
135
SLASH + projectFolder + SLASH + CAT_SCAN_SCRIPT ;
118
136
log (executeCommand (scriptCommand ));
119
137
// log output file
120
- final String path = config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING )) +
138
+ final String path = config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
139
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )) +
121
140
SLASH + projectFolder + SLASH + CAT_LOG_FILE ;
122
141
for (final String line : Files .readAllLines (Paths .get (path ))) {
123
142
log (line + NEW_LINE );
@@ -137,7 +156,6 @@ private String analyze(final String projectName, final String projectFolder, fin
137
156
LOGGER .severe (e .getMessage ());
138
157
}
139
158
140
-
141
159
};
142
160
final Future <?> execution = service .submit (task );
143
161
@@ -153,13 +171,13 @@ private String analyze(final String projectName, final String projectFolder, fin
153
171
service .shutdown ();
154
172
}
155
173
156
-
157
174
// return the complete logs
158
175
return getLogs ();
159
176
}
160
177
161
178
/**
162
179
* Export the sonar-project.properties in the corresponding folder
180
+ *
163
181
* @param path Output folder
164
182
* @param data Data to write
165
183
* @throws IOException when a file writing goes wrong
@@ -170,17 +188,18 @@ private void writeTextFile(final String path, final String data) throws IOExcept
170
188
171
189
// create the writer
172
190
// true to append; false to overwrite.
173
- try (FileWriter fileWriter = new FileWriter (spp , false )) {
191
+ try (FileWriter fileWriter = new FileWriter (spp , false )) {
174
192
// write the data
175
193
fileWriter .write (data );
176
194
}
177
195
}
178
196
179
197
/**
180
198
* Use the user's request to launch an scan
181
- * @param request request coming from the user
199
+ *
200
+ * @param request request coming from the user
182
201
* @param response response to send to the user
183
- * @throws IOException when communicating with the client
202
+ * @throws IOException when communicating with the client
184
203
* @throws InterruptedException ...
185
204
*/
186
205
@ Override
@@ -196,9 +215,11 @@ public void handle(final Request request, final Response response)
196
215
StringManager .string (StringManager .ANALYZE_FOLDER_NAME ));
197
216
final String sonarProjectProperties = request .mandatoryParam (
198
217
StringManager .string (StringManager .ANALYZE_SPP_NAME ));
218
+ final String qualityProfiles = request .mandatoryParam (
219
+ StringManager .string (StringManager .ANALYZE_QUALITY_PROFILES_NAME ));
199
220
200
221
// concrete scan
201
- final String result = analyze (projectName , workspace , sonarProjectProperties );
222
+ final String result = analyze (projectName , workspace , sonarProjectProperties , qualityProfiles );
202
223
203
224
// write the json response
204
225
try (JsonWriter jsonWriter = response .newJsonWriter ()) {
@@ -209,33 +230,83 @@ public void handle(final Request request, final Response response)
209
230
}
210
231
}
211
232
233
+ private String setupExternalTools (String qualityProfile ) {
234
+ StringBuilder setupExternalTools = new StringBuilder ();
235
+
236
+ Gson gson = new Gson ();
237
+ Type outerListType = new TypeToken <List <String >>() {
238
+ }.getType ();
239
+ List <String > outerList = gson .fromJson (qualityProfile , outerListType );
240
+ List <List <String >> qualityProfiles = new ArrayList <>();
241
+ for (String innerJson : outerList ) {
242
+ Type innerListType = new TypeToken <List <String >>() {
243
+ }.getType ();
244
+ List <String > innerList = gson .fromJson (innerJson , innerListType );
245
+ qualityProfiles .add (innerList );
246
+ }
247
+
248
+ for (List <String > qp : qualityProfiles ) {
249
+ if (qp .get (0 ).equals ("py" )) {
250
+ LOGGER .info ("Setup pylint" );
251
+ // Detect and run correct pylintrc according to RNC
252
+ String pylintrc = "/opt/python/pylintrc_RNC2015_D" ;
253
+ switch (qp .get (1 )) {
254
+ case "RNC A" :
255
+ pylintrc = "/opt/python/pylintrc_RNC2015_A_B" ;
256
+ break ;
257
+ case "RNC B" :
258
+ pylintrc = "/opt/python/pylintrc_RNC2015_A_B" ;
259
+ break ;
260
+ case "RNC C" :
261
+ pylintrc = "/opt/python/pylintrc_RNC2015_C" ;
262
+ break ;
263
+ default :
264
+ break ;
265
+ }
266
+ setupExternalTools .append (
267
+ "\n pylint --rcfile=" + pylintrc
268
+ + " --load-plugins=pylint_sonarjson --output-format=sonarjson --output=pylint-report.json *.py" );
269
+ }
270
+ if (qp .contains ("docker" )) {
271
+ LOGGER .info ("Setup hadolint" );
272
+ setupExternalTools .append (
273
+ "\n hadolint -f sonarqube --no-fail --config=/opt/hadolint/hadolint_RNC_A_B_C_D.yaml Dockerfile > hadolint-report.json" );
274
+ }
275
+ }
276
+ return setupExternalTools .toString ();
277
+ }
278
+
212
279
/**
213
- * Create a temporary script containing dedicated command executing sonar-scanner
214
- * @param project repository containing the source code
280
+ * Create a temporary script containing dedicated command executing
281
+ * sonar-scanner
282
+ *
283
+ * @param project repository containing the source code
215
284
* @param commandLine command line to execute
216
285
* @return The created file
217
286
*/
218
- private File createScript (final String project , final String commandLine ) {
287
+ private File createScript (final String project , final String commandLine , final String qualityProfiles ) {
219
288
// path to the workspace
220
- final String workspace = config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY )).orElse (StringManager .string (StringManager .DEFAULT_STRING ))+
221
- SLASH +project + SLASH ;
289
+ final String workspace = config .get (StringManager .string (StringManager .WORKSPACE_PROP_DEF_KEY ))
290
+ .orElse (StringManager .string (StringManager .DEFAULT_STRING )) +
291
+ SLASH + project + SLASH ;
222
292
// create script in a file located in the project's repository
223
293
final File scriptOutput = new File (workspace + CAT_SCAN_SCRIPT );
224
294
295
+ String setupExternalTools = setupExternalTools (qualityProfiles );
296
+
225
297
// Write all command lines in a single temporary script
226
298
try (
227
- FileWriter script = new FileWriter (scriptOutput )
228
- ){
229
- script .write ("#!/bin/bash -e" );
230
- script .write ("\n cd " +workspace );
231
- script .write (StringManager .string (StringManager .CNES_LOG_SEPARATOR )+commandLine );
232
- LOGGER .info ("commandLine : " + commandLine );
299
+ FileWriter script = new FileWriter (scriptOutput )) {
300
+ script .write ("#!/bin/bash" );
301
+ script .write ("\n cd " + workspace );
302
+ script .write ("\n " + setupExternalTools );
303
+ script .write (StringManager .string (StringManager .CNES_LOG_SEPARATOR ) + commandLine );
233
304
} catch (IOException e ) {
234
305
LOGGER .severe (e .getMessage ());
235
306
}
236
307
237
308
// give execution rights on the script
238
- if (!scriptOutput .setExecutable (true )) {
309
+ if (!scriptOutput .setExecutable (true )) {
239
310
LOGGER .severe (String .format (FILE_PERMISSIONS_ERROR , scriptOutput .getName ()));
240
311
}
241
312
0 commit comments