Skip to content

Commit 10d865d

Browse files
authored
SONARPY-2477 Collect data for Databricks notebooks (#2260)
1 parent 5b243a7 commit 10d865d

File tree

7 files changed

+67
-3
lines changed

7 files changed

+67
-3
lines changed

sonar-python-plugin/src/main/java/org/sonar/plugins/python/IPynbSensor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ private void processNotebooksFiles(List<PythonInputFile> pythonFiles, SensorCont
9393
PythonScanner scanner = new PythonScanner(context, checks, fileLinesContextFactory, noSonarFilter, PythonParser.createIPythonParser(), pythonIndexer);
9494
scanner.execute(pythonFiles, context);
9595
sensorTelemetryStorage.updateMetric(TelemetryMetricKey.NOTEBOOK_RECOGNITION_ERROR_KEY, scanner.getRecognitionErrorCount());
96+
updateDatabricksTelemetry(scanner);
9697
}
9798

9899
private List<PythonInputFile> parseNotebooks(List<PythonInputFile> pythonFiles, SensorContext context) {
@@ -135,4 +136,9 @@ private static List<PythonInputFile> getInputFiles(SensorContext context) {
135136
private static boolean isErrorOnTestFile(PythonInputFile inputFile) {
136137
return inputFile.wrappedFile().type() == InputFile.Type.TEST;
137138
}
139+
140+
private void updateDatabricksTelemetry(PythonScanner scanner) {
141+
sensorTelemetryStorage.updateMetric(TelemetryMetricKey.IPYNB_DATABRICKS_FOUND, scanner.getFoundDatabricks());
142+
}
143+
138144
}

sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonScanner.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Map;
3131
import java.util.Optional;
3232
import java.util.Set;
33+
import java.util.regex.Pattern;
3334
import javax.annotation.CheckForNull;
3435
import org.slf4j.Logger;
3536
import org.slf4j.LoggerFactory;
@@ -78,6 +79,8 @@ public class PythonScanner extends Scanner {
7879
private final PythonIndexer indexer;
7980
private final Map<PythonInputFile, Set<PythonCheck>> checksExecutedWithoutParsingByFiles = new HashMap<>();
8081
private int recognitionErrorCount = 0;
82+
private static final Pattern DATABRICKS_MAGIC_COMMAND_PATTERN = Pattern.compile("^\\h*#\\h*(MAGIC|COMMAND).*");
83+
private boolean foundDatabricks = false;
8184

8285
public PythonScanner(
8386
SensorContext context, PythonChecks checks,
@@ -150,6 +153,13 @@ protected void scanFile(PythonInputFile inputFile) throws IOException {
150153
new SymbolVisitor(context.newSymbolTable().onFile(inputFile.wrappedFile())).visitFileInput(visitorContext.rootTree());
151154
new PythonHighlighter(context, inputFile).scanFile(visitorContext);
152155
}
156+
157+
searchForDataBricks(visitorContext);
158+
}
159+
160+
private void searchForDataBricks(PythonVisitorContext visitorContext) {
161+
foundDatabricks |= visitorContext.pythonFile().content().lines().anyMatch(
162+
line -> DATABRICKS_MAGIC_COMMAND_PATTERN.matcher(line).matches());
153163
}
154164

155165
private static PythonTreeMaker getTreeMaker(PythonInputFile inputFile) {
@@ -407,4 +417,8 @@ private static TextRange rangeFromTextSpan(InputFile file, PythonTextEdit python
407417
public int getRecognitionErrorCount() {
408418
return recognitionErrorCount;
409419
}
420+
421+
public boolean getFoundDatabricks() {
422+
return foundDatabricks;
423+
}
410424
}

sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonSensor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,15 @@ public void execute(SensorContext context) {
131131
TypeShed.setProjectLevelSymbolTable(pythonIndexer.projectLevelSymbolTable());
132132
PythonScanner scanner = new PythonScanner(context, checks, fileLinesContextFactory, noSonarFilter, PythonParser.create(), pythonIndexer);
133133
scanner.execute(pythonFiles, context);
134+
updateDatabricksTelemetry(scanner);
134135
sensorTelemetryStorage.send(context);
135136
durationReport.stop();
136137
}
137138

139+
private void updateDatabricksTelemetry(PythonScanner scanner) {
140+
sensorTelemetryStorage.updateMetric(TelemetryMetricKey.PYTHON_DATABRICKS_FOUND, scanner.getFoundDatabricks());
141+
}
142+
138143
private void updatePythonVersionTelemetry(SensorContext context, String[] pythonVersionParameter) {
139144
if (context.runtime().getProduct() == SonarProduct.SONARLINT) {
140145
return;

sonar-python-plugin/src/main/java/org/sonar/plugins/python/SensorTelemetryStorage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ public void send(SensorContext sensorContext) {
3535
var apiVersion = sensorContext.runtime().getApiVersion();
3636
if (apiVersion.isGreaterThanOrEqual(Version.create(10, 9))) {
3737
data.forEach((k, v) -> {
38-
LOG.info("Collected metric: {}={}", k, v);
38+
LOG.debug("Collected metric: {}={}", k, v);
3939
sensorContext.addTelemetryProperty(k.key(), v);
4040
});
4141

4242
} else {
43-
LOG.info("Skipping sending metrics because the plugin API version is {}", apiVersion);
43+
LOG.debug("Skipping sending metrics because the plugin API version is {}", apiVersion);
4444
}
4545
} catch (Exception e) {
4646
LOG.error("Failed to send metrics", e);

sonar-python-plugin/src/main/java/org/sonar/plugins/python/TelemetryMetricKey.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ public enum TelemetryMetricKey {
2222
NOTEBOOK_RECOGNITION_ERROR_KEY("python.notebook.recognition_error"),
2323
NOTEBOOK_EXCEPTION_KEY("python.notebook.exceptions"),
2424
PYTHON_VERSION_SET_KEY("python.version.set"),
25-
PYTHON_VERSION_KEY("python.version");
25+
PYTHON_VERSION_KEY("python.version"),
26+
PYTHON_DATABRICKS_FOUND("python.notebook.databricks.python"),
27+
IPYNB_DATABRICKS_FOUND("python.notebook.databricks.ipynb");
2628

2729
private final String key;
2830

sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,36 @@ void send_telemetry_no_version() {
14381438
verify(contextSpy, times(1)).addTelemetryProperty(TelemetryMetricKey.PYTHON_VERSION_SET_KEY.key(), "0");
14391439
}
14401440

1441+
@Test
1442+
void detects_databricks() {
1443+
activeRules = new ActiveRulesBuilder()
1444+
.addRule(new NewActiveRule.Builder()
1445+
.setRuleKey(RuleKey.of(CheckList.REPOSITORY_KEY, "PrintStatementUsage"))
1446+
.setName("Print Statement Usage")
1447+
.build())
1448+
.build();
1449+
1450+
inputFile("databricks.py");
1451+
var spyContext = spy(context);
1452+
sensor().execute(spyContext);
1453+
verify(spyContext, times(1)).addTelemetryProperty(TelemetryMetricKey.PYTHON_DATABRICKS_FOUND.key(), "1");
1454+
}
1455+
1456+
@Test
1457+
void detects_databricks_negative() {
1458+
activeRules = new ActiveRulesBuilder()
1459+
.addRule(new NewActiveRule.Builder()
1460+
.setRuleKey(RuleKey.of(CheckList.REPOSITORY_KEY, "PrintStatementUsage"))
1461+
.setName("Print Statement Usage")
1462+
.build())
1463+
.build();
1464+
1465+
inputFile(FILE_1);
1466+
var spyContext = spy(context);
1467+
sensor().execute(spyContext);
1468+
verify(spyContext, times(1)).addTelemetryProperty(TelemetryMetricKey.PYTHON_DATABRICKS_FOUND.key(), "0");
1469+
}
1470+
14411471
private com.sonar.sslr.api.Token passToken(URI uri) {
14421472
return com.sonar.sslr.api.Token.builder()
14431473
.setType(PythonKeyword.PASS)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Databricks notebooks
2+
# COMMAND ----------
3+
4+
# MAGIC %md
5+
# MAGIC ## Alter tables
6+
7+
# COMMAND ----------

0 commit comments

Comments
 (0)