Skip to content
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

Programming exercises: Add R programming language template #9256

Merged
merged 17 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ dependencies {
implementation "de.jplag:python-3:${jplag_version}"
implementation "de.jplag:rust:${jplag_version}"
implementation "de.jplag:javascript:${jplag_version}"
implementation "de.jplag:rlang:${jplag_version}"
implementation "de.jplag:text:${jplag_version}"

// those are transitive dependencies of JPlag Text --> Stanford NLP
Expand Down
4 changes: 4 additions & 0 deletions docs/user/exercises/programming-exercise-features.inc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Instructors can still use those templates to generate programming exercises and
+----------------------+----------+---------+
| JavaScript | yes | yes |
+----------------------+----------+---------+
| R | yes | yes |
+----------------------+----------+---------+

- Not all ``templates`` support the same feature set and supported features can also change depending on the continuous integration system setup.
Depending on the feature set, some options might not be available during the creation of the programming exercise.
Expand Down Expand Up @@ -71,6 +73,8 @@ Instructors can still use those templates to generate programming exercises and
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
| JavaScript | no | no | yes | no | n/a | no | no | L: yes, J: no |
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
| R | no | no | yes | no | n/a | no | no | L: yes, J: no |
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
magaupp marked this conversation as resolved.
Show resolved Hide resolved

- *Sequential Test Runs*: ``Artemis`` can generate a build plan which first executes structural and then behavioral tests. This feature can help students to better concentrate on the immediate challenge at hand.
- *Static Code Analysis*: ``Artemis`` can generate a build plan which additionally executes static code analysis tools.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import de.jplag.options.JPlagOptions;
import de.jplag.python3.PythonLanguage;
import de.jplag.reporting.reportobject.ReportObjectFactory;
import de.jplag.rlang.RLanguage;
import de.jplag.rust.RustLanguage;
import de.jplag.swift.SwiftLanguage;
import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException;
Expand Down Expand Up @@ -317,7 +318,8 @@ private Language getJPlagProgrammingLanguage(ProgrammingExercise programmingExer
case KOTLIN -> new KotlinLanguage();
case RUST -> new RustLanguage();
case JAVASCRIPT -> new JavaScriptLanguage();
case EMPTY, PHP, DART, HASKELL, ASSEMBLER, OCAML, C_SHARP, C_PLUS_PLUS, SQL, R, TYPESCRIPT, GO, MATLAB, BASH, VHDL, RUBY, POWERSHELL, ADA ->
case R -> new RLanguage();
case EMPTY, PHP, DART, HASKELL, ASSEMBLER, OCAML, C_SHARP, C_PLUS_PLUS, SQL, TYPESCRIPT, GO, MATLAB, BASH, VHDL, RUBY, POWERSHELL, ADA ->
magaupp marked this conversation as resolved.
Show resolved Hide resolved
throw new BadRequestAlertException("Programming language " + programmingExercise.getProgrammingLanguage() + " not supported for plagiarism check.",
"ProgrammingExercise", "notSupported");
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public enum ProgrammingLanguage {
SWIFT,
OCAML,
RUST,
JAVASCRIPT
JAVASCRIPT,
R
magaupp marked this conversation as resolved.
Show resolved Hide resolved
);
// @formatter:on

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public TemplateUpgradePolicyService(JavaTemplateUpgradeService javaRepositoryUpg
public TemplateUpgradeService getUpgradeService(ProgrammingLanguage programmingLanguage) {
return switch (programmingLanguage) {
case JAVA -> javaRepositoryUpgradeService;
case KOTLIN, PYTHON, C, HASKELL, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT -> defaultRepositoryUpgradeService;
case C_SHARP, C_PLUS_PLUS, SQL, R, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
case KOTLIN, PYTHON, C, HASKELL, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT, R -> defaultRepositoryUpgradeService;
case C_SHARP, C_PLUS_PLUS, SQL, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
throw new UnsupportedOperationException("Unsupported programming language: " + programmingLanguage);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ enum RepositoryCheckoutPath implements CustomizableCheckoutPath {
@Override
public String forProgrammingLanguage(ProgrammingLanguage language) {
return switch (language) {
case JAVA, PYTHON, C, HASKELL, KOTLIN, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT -> "assignment";
case C_SHARP, C_PLUS_PLUS, SQL, R, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
case JAVA, PYTHON, C, HASKELL, KOTLIN, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT, R -> "assignment";
case C_SHARP, C_PLUS_PLUS, SQL, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
throw new UnsupportedOperationException("Unsupported programming language: " + language);
};
}
Expand All @@ -230,9 +230,9 @@ public String forProgrammingLanguage(ProgrammingLanguage language) {
@Override
public String forProgrammingLanguage(ProgrammingLanguage language) {
return switch (language) {
case JAVA, PYTHON, HASKELL, KOTLIN, SWIFT, EMPTY, RUST, JAVASCRIPT -> "";
case JAVA, PYTHON, HASKELL, KOTLIN, SWIFT, EMPTY, RUST, JAVASCRIPT, R -> "";
case C, VHDL, ASSEMBLER, OCAML -> "tests";
case C_SHARP, C_PLUS_PLUS, SQL, R, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
case C_SHARP, C_PLUS_PLUS, SQL, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
magaupp marked this conversation as resolved.
Show resolved Hide resolved
throw new UnsupportedOperationException("Unsupported programming language: " + language);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.EMPTY;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVA;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVASCRIPT;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.R;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.RUST;
import static de.tum.cit.aet.artemis.programming.domain.ProjectType.MAVEN_MAVEN;
import static de.tum.cit.aet.artemis.programming.domain.ProjectType.PLAIN_MAVEN;
Expand All @@ -27,5 +28,6 @@ public GitLabCIProgrammingLanguageFeatureService() {
programmingLanguageFeatures.put(JAVA, new ProgrammingLanguageFeature(JAVA, false, false, false, true, false, List.of(PLAIN_MAVEN, MAVEN_MAVEN), false, false));
programmingLanguageFeatures.put(RUST, new ProgrammingLanguageFeature(RUST, false, false, true, false, false, List.of(), false, false));
programmingLanguageFeatures.put(JAVASCRIPT, new ProgrammingLanguageFeature(JAVASCRIPT, false, false, true, false, false, List.of(), false, false));
programmingLanguageFeatures.put(R, new ProgrammingLanguageFeature(R, false, false, true, false, false, List.of(), false, false));
magaupp marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVASCRIPT;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.KOTLIN;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.PYTHON;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.R;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.RUST;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.SWIFT;
import static de.tum.cit.aet.artemis.programming.domain.ProjectType.FACT;
Expand Down Expand Up @@ -43,5 +44,6 @@ public JenkinsProgrammingLanguageFeatureService() {
programmingLanguageFeatures.put(HASKELL, new ProgrammingLanguageFeature(HASKELL, false, false, false, false, true, List.of(), false, false));
programmingLanguageFeatures.put(RUST, new ProgrammingLanguageFeature(RUST, false, false, true, false, false, List.of(), false, false));
programmingLanguageFeatures.put(JAVASCRIPT, new ProgrammingLanguageFeature(JAVASCRIPT, false, false, true, false, false, List.of(), false, false));
programmingLanguageFeatures.put(R, new ProgrammingLanguageFeature(R, false, false, true, false, false, List.of(), false, false));
magaupp marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ private JenkinsXmlConfigBuilder builderFor(ProgrammingLanguage programmingLangua
throw new UnsupportedOperationException("Xcode templates are not available for Jenkins.");
}
return switch (programmingLanguage) {
case JAVA, KOTLIN, PYTHON, C, HASKELL, SWIFT, EMPTY, RUST, JAVASCRIPT -> jenkinsBuildPlanCreator;
case VHDL, ASSEMBLER, OCAML, C_SHARP, C_PLUS_PLUS, SQL, R, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
case JAVA, KOTLIN, PYTHON, C, HASKELL, SWIFT, EMPTY, RUST, JAVASCRIPT, R -> jenkinsBuildPlanCreator;
case VHDL, ASSEMBLER, OCAML, C_SHARP, C_PLUS_PLUS, SQL, TYPESCRIPT, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
magaupp marked this conversation as resolved.
Show resolved Hide resolved
throw new UnsupportedOperationException(programmingLanguage + " templates are not available for Jenkins.");
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.KOTLIN;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.OCAML;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.PYTHON;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.R;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.RUST;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.SWIFT;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.VHDL;
Expand Down Expand Up @@ -51,5 +52,6 @@ public LocalCIProgrammingLanguageFeatureService() {
programmingLanguageFeatures.put(SWIFT, new ProgrammingLanguageFeature(SWIFT, false, false, true, true, false, List.of(PLAIN), false, true));
programmingLanguageFeatures.put(RUST, new ProgrammingLanguageFeature(RUST, false, false, true, false, false, List.of(), false, true));
programmingLanguageFeatures.put(JAVASCRIPT, new ProgrammingLanguageFeature(JAVASCRIPT, false, false, true, false, false, List.of(), false, true));
programmingLanguageFeatures.put(R, new ProgrammingLanguageFeature(R, false, false, true, false, false, List.of(), false, true));
magaupp marked this conversation as resolved.
Show resolved Hide resolved
}
}
2 changes: 2 additions & 0 deletions src/main/resources/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ artemis:
default: "ghcr.io/ls1intum/artemis-rust-docker:v0.9.70"
javascript:
default: "ghcr.io/ls1intum/artemis-javascript-docker:v1.0.0"
r:
default: "ghcr.io/ls1intum/artemis-r-docker:v1.0.0"
magaupp marked this conversation as resolved.
Show resolved Hide resolved

management:
endpoints:
Expand Down
26 changes: 26 additions & 0 deletions src/main/resources/templates/aeolus/r/default.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
export AEOLUS_INITIAL_DIRECTORY=${PWD}
install () {
echo '⚙️ executing install'
R CMD INSTALL assignment
}

run_all_tests () {
echo '⚙️ executing run_all_tests'
Rscript -e 'library("testthat"); options(testthat.output_file = "junit.xml"); test_local(".", reporter = "junit")'
}

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; install"
cd "${AEOLUS_INITIAL_DIRECTORY}"
bash -c "source ${_script_name} aeolus_sourcing; run_all_tests"
}

main "${@}"
14 changes: 14 additions & 0 deletions src/main/resources/templates/aeolus/r/default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
api: v0.0.1
metadata:
name: R
id: r
description: Test package using testthat
actions:
- name: install
script: R CMD INSTALL assignment
- name: run_all_tests
script: Rscript -e 'library("testthat"); options(testthat.output_file = "junit.xml"); test_local(".", reporter = "junit")'
results:
- name: junit
path: tests/testthat/junit.xml
type: junit
48 changes: 48 additions & 0 deletions src/main/resources/templates/gitlabci/r/regularRuns/.gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
stages:
- test
- upload


test-job:
image: ${ARTEMIS_BUILD_DOCKER_IMAGE}
stage: test
only:
variables:
- $CI_COMMIT_BRANCH == $ARTEMIS_SUBMISSION_GIT_BRANCH
allow_failure: true
variables:
GIT_STRATEGY: none
script:
- git clone --branch ${ARTEMIS_TEST_GIT_BRANCH} ${CI_SERVER_PROTOCOL}://${ARTEMIS_TEST_GIT_USER}:${ARTEMIS_TEST_GIT_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/${CI_PROJECT_NAMESPACE}/${ARTEMIS_TEST_GIT_REPOSITORY_SLUG} .
- git clone --branch ${ARTEMIS_SUBMISSION_GIT_BRANCH} ${CI_SERVER_PROTOCOL}://${ARTEMIS_TEST_GIT_USER}:${ARTEMIS_TEST_GIT_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME} assignment
- export ARTEMIS_NOTIFICATION_SECRET=[hidden] # Workaround for overwriting the secret
- export ARTEMIS_TEST_GIT_TOKEN=[hidden]
- R CMD INSTALL assignment | tee -a "${ARTEMIS_BUILD_LOGS_FILE}" && echo "ARTEMIS_BUILD_STATUS=success" > .env || echo "ARTEMIS_BUILD_STATUS=failed" > .env
- Rscript -e 'library("testthat"); options(testthat.output_file = "junit.xml"); test_local(".", reporter = "junit")' | tee -a "${ARTEMIS_BUILD_LOGS_FILE}"
- test -e tests/testthat/junit.xml && sed -i 's/<testsuites[^>]*>/<testsuite>/g ; s/<\/testsuites>/<\/testsuite>/g' tests/testthat/junit.xml # <testsuites> not supported by notification plugin
after_script:
- echo "ARTEMIS_TEST_GIT_HASH=$(git rev-parse HEAD)" >> .env
- echo "ARTEMIS_SUBMISSION_GIT_HASH=${CI_COMMIT_SHA}" >> .env
- echo "ARTEMIS_SUBMISSION_GIT_REPOSITORY_SLUG=${CI_PROJECT_NAME}" >> .env
artifacts:
paths:
- ${ARTEMIS_BUILD_LOGS_FILE}
- tests/testthat/*.xml
reports:
dotenv: .env


upload-job:
image: ${ARTEMIS_NOTIFICATION_PLUGIN_DOCKER_IMAGE}
stage: upload
dependencies:
- test-job
only:
variables:
- $CI_COMMIT_BRANCH == $ARTEMIS_SUBMISSION_GIT_BRANCH
variables:
GIT_STRATEGY: none
script:
- cp -r /notification-plugin/* .
- export ARTEMIS_TEST_RESULTS_DIR="tests/testthat" # override project variable
- gradle run
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* This file configures the actual build steps for the automatic grading.
*
* !!!
* For regular exercises, there is no need to make changes to this file.
* Only this base configuration is actively supported by the Artemis maintainers
* and/or your Artemis instance administrators.
* !!!
*/

dockerImage = '#dockerImage'
dockerFlags = '#dockerArgs'

/**
* Main function called by Jenkins.
*/
void testRunner() {
docker.image(dockerImage).inside(dockerFlags) { c ->
runTestSteps()
}
}

private void runTestSteps() {
test()
}

/**
* Run unit tests
*/
private void test() {
stage('Test') {
sh '''
R CMD INSTALL assignment
Rscript -e 'library("testthat"); options(testthat.output_file = "junit.xml"); test_local(".", reporter = "junit")'
'''
}
}

/**
* Script of the post build tasks aggregating all JUnit files in $WORKSPACE/results.
*
* Called by Jenkins.
*/
void postBuildTasks() {
sh '''
rm -rf results
mkdir results
if [ -e tests/testthat/junit.xml ]
then
sed -i 's/<testsuites[^>]*>/<testsuite>/g ; s/<\\/testsuites>/<\\/testsuite>/g' tests/testthat/junit.xml
fi
cp tests/testthat/junit.xml $WORKSPACE/results/ || true
sed -i 's/[^[:print:]\t]/�/g' $WORKSPACE/results/*.xml || true
'''
}

// very important, do not remove
// required so that Jenkins finds the methods defined in this script
return this
7 changes: 7 additions & 0 deletions src/main/resources/templates/r/exercise/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Package: assignment
Title: Artemis R Student Assignment
Version: 0.0.0.9000
Author: Artemis
Description: This is an assignment to be solved by students.
License: MIT
Encoding: UTF-8
1 change: 1 addition & 0 deletions src/main/resources/templates/r/exercise/NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exportPattern("^[^\\.]")
3 changes: 3 additions & 0 deletions src/main/resources/templates/r/exercise/R/convert.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
matrix_to_column_list <- function(mat) {
# TODO: implement
}
magaupp marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 6 additions & 0 deletions src/main/resources/templates/r/readme
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Matrix Columns

Write a function `matrix_to_column_list` in R that takes a matrix of any shape and converts it into a list of
column-vectors. Each element of the list should represent a column of the matrix.

1. [task][Convert to column-vectors](converts_3x3_matrix_to_vectors,converts_4x2_matrix_to_vectors,converts_1x5_matrix_to_scalars,converts_5x1_matrix_to_vector)
7 changes: 7 additions & 0 deletions src/main/resources/templates/r/solution/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Package: assignment
Title: Artemis R Student Assignment
Version: 0.0.0.9000
Author: Artemis
Description: This is an assignment to be solved by students.
License: MIT
Encoding: UTF-8
1 change: 1 addition & 0 deletions src/main/resources/templates/r/solution/NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exportPattern("^[^\\.]")
17 changes: 17 additions & 0 deletions src/main/resources/templates/r/solution/R/convert.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
matrix_to_column_list <- function(mat) {
if (!is.matrix(mat)) {
stop("Input must be a matrix")
}

n_cols <- ncol(mat)

# Initialize an empty list to store column-vectors
column_list <- vector("list", length = n_cols)

# Loop through each column and store it in the list
for (i in 1:n_cols) {
column_list[[i]] <- mat[, i]
}

return(column_list)
}
magaupp marked this conversation as resolved.
Show resolved Hide resolved
14 changes: 14 additions & 0 deletions src/main/resources/templates/r/test/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Package: test
Title: Artemis R Tests
Version: 0.0.0.9000
Author: Artemis
Description: This package tests the student assignment.
License: MIT
Encoding: UTF-8
Imports:
assignment
Remotes:
local::./assignment
Suggests:
testthat (>= 3.0.0)
Config/testthat/edition: 3
12 changes: 12 additions & 0 deletions src/main/resources/templates/r/test/tests/testthat.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file is part of the standard setup for testthat.
# It is recommended that you do not modify it.
#
# Where should you do additional test configuration?
# Learn more about the roles of various files in:
# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
# * https://testthat.r-lib.org/articles/special-files.html

library(testthat)
library(tests)

test_check("tests")
Loading
Loading