diff --git a/src/main/java/de/tum/cit/aet/artemis/core/config/StaticCodeAnalysisConfigurer.java b/src/main/java/de/tum/cit/aet/artemis/core/config/StaticCodeAnalysisConfigurer.java index 54ef93ca02c7..703d6ffeb537 100644 --- a/src/main/java/de/tum/cit/aet/artemis/core/config/StaticCodeAnalysisConfigurer.java +++ b/src/main/java/de/tum/cit/aet/artemis/core/config/StaticCodeAnalysisConfigurer.java @@ -13,8 +13,73 @@ */ public class StaticCodeAnalysisConfigurer { + // @formatter:off + private static final List CATEGORY_NAMES_PYTHON = List.of( + "Pyflakes", + "pycodestyle", + "mccabe", + "isort", + "pep8-naming", + "pydocstyle", + "pyupgrade", + "flake8-2020", + "flake8-annotations", + "flake8-async", + "flake8-bandit", + "flake8-blind-except", + "flake8-boolean-trap", + "flake8-bugbear", + "flake8-builtins", + "flake8-commas", + "flake8-copyright", + "flake8-comprehensions", + "flake8-datetimez", + "flake8-debugger", + "flake8-django", + "flake8-errmsg", + "flake8-executable", + "flake8-future-annotations", + "flake8-implicit-str-concat", + "flake8-import-conventions", + "flake8-logging", + "flake8-logging-format", + "flake8-no-pep420", + "flake8-pie", + "flake8-print", + "flake8-pyi", + "flake8-pytest-style", + "flake8-quotes", + "flake8-raise", + "flake8-return", + "flake8-self", + "flake8-slots", + "flake8-simplify", + "flake8-tidy-imports", + "flake8-type-checking", + "flake8-gettext", + "flake8-unused-arguments", + "flake8-use-pathlib", + "flake8-todos", + "flake8-fixme", + "eradicate", + "pandas-vet", + "pygrep-hooks", + "Pylint", + "tryceratops", + "flynt", + "NumPy-specific rules", + "FastAPI", + "Airflow", + "Perflint", + "refurb", + "pydoclint", + "Ruff-specific rules" + ); + // @formatter:on + private static final Map> languageToDefaultCategories = Map.of(ProgrammingLanguage.JAVA, - createDefaultCategoriesForJava(), ProgrammingLanguage.SWIFT, createDefaultCategoriesForSwift(), ProgrammingLanguage.C, createDefaultCategoriesForC()); + createDefaultCategoriesForJava(), ProgrammingLanguage.SWIFT, createDefaultCategoriesForSwift(), ProgrammingLanguage.C, createDefaultCategoriesForC(), + ProgrammingLanguage.PYTHON, createDefaultCategoriesForPython()); /** * Create an unmodifiable List of default static code analysis categories for Java @@ -85,6 +150,11 @@ private static List createDefaultCategoriesFo new StaticCodeAnalysisDefaultCategory("Miscellaneous", 0.2D, 2D, CategoryState.INACTIVE, List.of(createMapping(StaticCodeAnalysisTool.GCC, "Misc")))); } + private static List createDefaultCategoriesForPython() { + return CATEGORY_NAMES_PYTHON.stream() + .map(name -> new StaticCodeAnalysisDefaultCategory(name, 0.0, 1.0, CategoryState.FEEDBACK, List.of(createMapping(StaticCodeAnalysisTool.RUFF, name)))).toList(); + } + public static Map> staticCodeAnalysisConfiguration() { return languageToDefaultCategories; } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/domain/StaticCodeAnalysisTool.java b/src/main/java/de/tum/cit/aet/artemis/programming/domain/StaticCodeAnalysisTool.java index a3ebd056ebbd..8b205445ddd7 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/domain/StaticCodeAnalysisTool.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/domain/StaticCodeAnalysisTool.java @@ -17,6 +17,7 @@ public enum StaticCodeAnalysisTool { PMD_CPD(ProgrammingLanguage.JAVA, "cpd.xml"), SWIFTLINT(ProgrammingLanguage.SWIFT, "swiftlint-result.xml"), GCC(ProgrammingLanguage.C, "gcc.xml"), + RUFF(ProgrammingLanguage.PYTHON, "ruff.sarif"), ; // @formatter:on diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIProgrammingLanguageFeatureService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIProgrammingLanguageFeatureService.java index d86199310720..f759f7711ab5 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIProgrammingLanguageFeatureService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIProgrammingLanguageFeatureService.java @@ -51,7 +51,7 @@ public LocalCIProgrammingLanguageFeatureService() { programmingLanguageFeatures.put(JAVASCRIPT, new ProgrammingLanguageFeature(JAVASCRIPT, false, false, true, false, false, List.of(), false, true)); programmingLanguageFeatures.put(KOTLIN, new ProgrammingLanguageFeature(KOTLIN, false, false, true, true, false, List.of(), false, true)); programmingLanguageFeatures.put(OCAML, new ProgrammingLanguageFeature(OCAML, false, false, false, false, true, List.of(), false, true)); - programmingLanguageFeatures.put(PYTHON, new ProgrammingLanguageFeature(PYTHON, false, false, true, false, false, List.of(), false, true)); + programmingLanguageFeatures.put(PYTHON, new ProgrammingLanguageFeature(PYTHON, false, true, true, false, false, List.of(), false, true)); programmingLanguageFeatures.put(R, new ProgrammingLanguageFeature(R, false, false, true, false, false, List.of(), false, true)); programmingLanguageFeatures.put(RUST, new ProgrammingLanguageFeature(RUST, false, false, true, false, false, List.of(), false, true)); programmingLanguageFeatures.put(SWIFT, new ProgrammingLanguageFeature(SWIFT, false, false, true, true, false, List.of(PLAIN), false, true)); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/ParserPolicy.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/ParserPolicy.java index fa90c31c7c9d..43b263c7d282 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/ParserPolicy.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/ParserPolicy.java @@ -4,6 +4,8 @@ import de.tum.cit.aet.artemis.programming.domain.StaticCodeAnalysisTool; import de.tum.cit.aet.artemis.programming.service.localci.scaparser.exception.UnsupportedToolException; +import de.tum.cit.aet.artemis.programming.service.localci.scaparser.strategy.sarif.RuffCategorizer; +import de.tum.cit.aet.artemis.programming.service.localci.scaparser.strategy.sarif.SarifParser; /** * Policy class for the parser strategies. @@ -27,7 +29,7 @@ public ParserStrategy configure(String fileName) { case CHECKSTYLE -> new CheckstyleParser(); case PMD -> new PMDParser(); case PMD_CPD -> new PMDCPDParser(); - // so far, we do not support swiftlint and gcc only SCA for Java + case RUFF -> new SarifParser(StaticCodeAnalysisTool.RUFF, new RuffCategorizer()); default -> throw new UnsupportedToolException("Tool " + tool + " is not supported"); }; } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/RuffCategorizer.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/RuffCategorizer.java new file mode 100644 index 000000000000..cc572dbb4342 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/scaparser/strategy/sarif/RuffCategorizer.java @@ -0,0 +1,9 @@ +package de.tum.cit.aet.artemis.programming.service.localci.scaparser.strategy.sarif; + +public class RuffCategorizer implements RuleCategorizer { + + @Override + public String categorizeRule(ReportingDescriptor rule) { + return rule.getProperties().getAdditionalProperties().getOrDefault("kind", "Unknown").toString(); + } +} diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 85965bb400e0..6aba0a2b5349 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -71,7 +71,7 @@ artemis: empty: default: "ubuntu:24.04" python: - default: "ls1tum/artemis-python-docker:latest" + default: "ls1tum/artemis-python-docker:pr-3" c: # possible overrides: gcc, fact default: "ls1tum/artemis-c-docker:latest" diff --git a/src/main/resources/templates/aeolus/python/default_static.sh b/src/main/resources/templates/aeolus/python/default_static.sh new file mode 100644 index 000000000000..bdda9592acd3 --- /dev/null +++ b/src/main/resources/templates/aeolus/python/default_static.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -e +export AEOLUS_INITIAL_DIRECTORY=${PWD} +static_code_analysis () { + echo '⚙️ executing static_code_analysis' + ruff check --output-format=sarif --output-file=ruff.sarif --exit-zero --select=ALL "${studentParentWorkingDirectoryName}" +} + +build_and_test_the_code () { + echo '⚙️ executing build_and_test_the_code' + python3 -m compileall . -q || error=true + if [ ! $error ] + then + pytest --junitxml=test-reports/results.xml + fi +} + +main () { + if [[ "${1}" == "aeolus_sourcing" ]]; then + return 0 # just source to use the methods in the subshell, no execution + fi + local _script_name + _script_name=${BASH_SOURCE[0]:-$0} + cd "${AEOLUS_INITIAL_DIRECTORY}" + bash -c "source ${_script_name} aeolus_sourcing; static_code_analysis" + cd "${AEOLUS_INITIAL_DIRECTORY}" + bash -c "source ${_script_name} aeolus_sourcing; build_and_test_the_code" +} + +main "${@}" diff --git a/src/main/resources/templates/aeolus/python/default_static.yaml b/src/main/resources/templates/aeolus/python/default_static.yaml new file mode 100644 index 000000000000..c67c45e5f9d7 --- /dev/null +++ b/src/main/resources/templates/aeolus/python/default_static.yaml @@ -0,0 +1,21 @@ +api: v0.0.1 +actions: + - name: static_code_analysis + script: ruff check --output-format=sarif --output-file=ruff.sarif --exit-zero --select=ALL "${studentParentWorkingDirectoryName}" + results: + - name: ruff + path: ruff.sarif + type: sca + - name: build_and_test_the_code + script: |- + python3 -m compileall . -q || error=true + if [ ! $error ] + then + pytest --junitxml=test-reports/results.xml + fi + runAlways: false + results: + - name: junit_test-reports/*results.xml + path: test-reports/*results.xml + type: junit + before: true diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/util/ProgrammingExerciseFactory.java b/src/test/java/de/tum/cit/aet/artemis/programming/util/ProgrammingExerciseFactory.java index e4dca9d8be57..839f00845078 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/util/ProgrammingExerciseFactory.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/util/ProgrammingExerciseFactory.java @@ -341,6 +341,7 @@ private static StaticCodeAnalysisIssue generateStaticCodeAnalysisIssue(StaticCod case PMD_CPD -> "Copy/Paste Detection"; case SWIFTLINT -> "swiftLint"; // TODO: rene: set better value after categories are better defined case GCC -> "Memory"; + case RUFF -> "Pylint"; }; return new StaticCodeAnalysisIssue(Constants.STUDENT_WORKING_DIRECTORY + "/www/packagename/Class1.java", // filePath