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 Go programming language template #9751

Merged
merged 25 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a1b0093
Add basic Go programming exercise template
magaupp Nov 11, 2024
3247ac8
Enable Go language features
magaupp Nov 11, 2024
e426259
Use strategy pattern example
magaupp Nov 16, 2024
7d77cc4
Add readme
magaupp Nov 24, 2024
72ca934
Remove useless comments
magaupp Nov 24, 2024
7de45a4
Mention getters and setters in readme
magaupp Nov 24, 2024
8501ff1
Add go image to test config
magaupp Nov 24, 2024
630ebb6
Add Jenkins support
magaupp Nov 24, 2024
7fd654e
Update documentation
magaupp Nov 24, 2024
23fdf50
Format imports
magaupp Nov 24, 2024
0ea99dd
Use more ideomatic implementation for MergeSort
magaupp Nov 24, 2024
66a0c50
Support custom exercise directory
magaupp Nov 24, 2024
4ad4608
Add constructors to readme
magaupp Nov 24, 2024
36a00d6
Support custom package names
magaupp Nov 26, 2024
dccf920
Fix tests
magaupp Nov 26, 2024
8751382
Fix incorrect test failure message
magaupp Nov 26, 2024
f7a1eb3
Fix incorrect test reference in readme
magaupp Nov 26, 2024
1fe934b
Update documentation to include package name
magaupp Nov 26, 2024
b738b05
Use more conventional package name in error message
magaupp Nov 26, 2024
a12954f
Avoid package name conflicts
magaupp Nov 27, 2024
2560b04
Improve reporting of build failures
magaupp Nov 27, 2024
0938faa
Consistently use pointer receivers
magaupp Nov 28, 2024
c72606a
Use unique names for tests throughout packages
magaupp Dec 19, 2024
a7585f7
Remove testsuite names from problem statement tasks
magaupp Dec 19, 2024
64141f9
Merge branch 'develop' into feature/programming-exercises/go-template
magaupp Dec 19, 2024
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 @@ -242,6 +242,7 @@ dependencies {
implementation "de.jplag:c:${jplag_version}"
implementation "de.jplag:cpp:${jplag_version}"
implementation "de.jplag:csharp:${jplag_version}"
implementation "de.jplag:golang:${jplag_version}"
implementation "de.jplag:java:${jplag_version}"
implementation "de.jplag:javascript:${jplag_version}"
implementation "de.jplag:kotlin:${jplag_version}"
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 @@ -45,6 +45,8 @@ Instructors can still use those templates to generate programming exercises and
+----------------------+----------+---------+
| C# | yes | yes |
+----------------------+----------+---------+
| Go | 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 @@ -87,6 +89,8 @@ Instructors can still use those templates to generate programming exercises and
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
| C# | no | no | yes | no | n/a | no | no | L: yes, J: no |
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
| Go | no | no | yes | yes | n/a | no | no | L: yes, J: no |
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+

- *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 @@ -33,6 +33,7 @@
import de.jplag.cpp.CPPLanguage;
import de.jplag.csharp.CSharpLanguage;
import de.jplag.exceptions.ExitException;
import de.jplag.golang.GoLanguage;
import de.jplag.java.JavaLanguage;
import de.jplag.javascript.JavaScriptLanguage;
import de.jplag.kotlin.KotlinLanguage;
Expand Down Expand Up @@ -317,6 +318,7 @@ private Language getJPlagProgrammingLanguage(ProgrammingExercise programmingExer
case C -> new CLanguage();
case C_PLUS_PLUS -> new CPPLanguage();
case C_SHARP -> new CSharpLanguage();
case GO -> new GoLanguage();
case JAVA -> new JavaLanguage();
case JAVASCRIPT -> new JavaScriptLanguage();
case KOTLIN -> new KotlinLanguage();
Expand All @@ -325,7 +327,7 @@ private Language getJPlagProgrammingLanguage(ProgrammingExercise programmingExer
case RUST -> new RustLanguage();
case SWIFT -> new SwiftLanguage();
case TYPESCRIPT -> new TypeScriptLanguage();
case EMPTY, PHP, DART, HASKELL, ASSEMBLER, OCAML, SQL, GO, MATLAB, BASH, VHDL, RUBY, POWERSHELL, ADA -> throw new BadRequestAlertException(
case EMPTY, PHP, DART, HASKELL, ASSEMBLER, OCAML, SQL, MATLAB, BASH, VHDL, RUBY, POWERSHELL, ADA -> 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 @@ -42,6 +42,7 @@ public enum ProgrammingLanguage {
C,
C_PLUS_PLUS,
C_SHARP,
GO,
magaupp marked this conversation as resolved.
Show resolved Hide resolved
HASKELL,
JAVA,
JAVASCRIPT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ void replacePlaceholders(final ProgrammingExercise programmingExercise, final Re
replacements.put(PACKAGE_NAME_PLACEHOLDER, programmingExercise.getPackageName());
}
case SWIFT -> replaceSwiftPlaceholders(replacements, programmingExercise, repository);
case GO -> replacements.put(PACKAGE_NAME_PLACEHOLDER, programmingExercise.getPackageName());
default -> {
// no special package name replacements needed for other programming languages
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,27 @@ public class ProgrammingExerciseService {
* (<a href="https://docs.oracle.com/javase/specs/jls/se14/html/jls-7.html#jls-7.4.1">https://docs.oracle.com/javase/specs/jls/se14/html/jls-7.html#jls-7.4.1</a>)
* with the restriction to a-z,A-Z,_ as "Java letter" and 0-9 as digits due to JavaScript/Browser Unicode character class limitations
*/
private static final String PACKAGE_NAME_REGEX = "^(?!.*(?:\\.|^)(?:abstract|continue|for|new|switch|assert|default|if|package|synchronized|boolean|do|goto|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while|_|true|false|null)(?:\\.|$))[A-Z_a-z]\\w*(?:\\.[A-Z_a-z]\\w*)*$";
private static final String PACKAGE_NAME_REGEX_FOR_JAVA_KOTLIN = "^(?!.*(?:\\.|^)(?:abstract|continue|for|new|switch|assert|default|if|package|synchronized|boolean|do|goto|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while|_|true|false|null)(?:\\.|$))[A-Z_a-z]\\w*(?:\\.[A-Z_a-z]\\w*)*$";

/**
* Swift package name Regex derived from
* (<a href="https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID412">https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID412</a>),
* with the restriction to a-z,A-Z as "Swift letter" and 0-9 as digits where no separators are allowed
*/
private static final String SWIFT_PACKAGE_NAME_REGEX = "^(?!(?:associatedtype|class|deinit|enum|extension|fileprivate|func|import|init|inout|internal|let|open|operator|private|protocol|public|rethrows|static|struct|subscript|typealias|var|break|case|continue|default|defer|do|else|fallthrough|for|guard|if|in|repeat|return|switch|where|while|as|Any|catch|false|is|nil|super|self|Self|throw|throws|true|try|_|[sS]wift)$)[A-Za-z][\\dA-Za-z]*$";
private static final String PACKAGE_NAME_REGEX_FOR_SWIFT = "^(?!(?:associatedtype|class|deinit|enum|extension|fileprivate|func|import|init|inout|internal|let|open|operator|private|protocol|public|rethrows|static|struct|subscript|typealias|var|break|case|continue|default|defer|do|else|fallthrough|for|guard|if|in|repeat|return|switch|where|while|as|Any|catch|false|is|nil|super|self|Self|throw|throws|true|try|_|[sS]wift)$)[A-Za-z][\\dA-Za-z]*$";

private final Pattern packageNamePattern = Pattern.compile(PACKAGE_NAME_REGEX);
/**
* Go package name Regex derived from <a href="https://go.dev/ref/spec#Package_clause">The Go Programming Language Specification</a> limited to ASCII. Package names are
* identifiers.
* They allow letters, digits and underscore. They cannot start with a digit. The package name cannot be a keyword or "_".
*/
private static final String PACKAGE_NAME_REGEX_FOR_GO = "^(?!(?:break|default|func|interface|select|case|defer|go|map|struct|chan|else|goto|package|switch|const|fallthrough|if|range|type|continue|for|import|return|var|_)$)[A-Za-z_][A-Za-z0-9_]*$";

private static final Pattern PACKAGE_NAME_PATTERN_FOR_JAVA_KOTLIN = Pattern.compile(PACKAGE_NAME_REGEX_FOR_JAVA_KOTLIN);

private final Pattern packageNamePatternForSwift = Pattern.compile(SWIFT_PACKAGE_NAME_REGEX);
private static final Pattern PACKAGE_NAME_PATTERN_FOR_SWIFT = Pattern.compile(PACKAGE_NAME_REGEX_FOR_SWIFT);

private static final Pattern PACKAGE_NAME_PATTERN_FOR_GO = Pattern.compile(PACKAGE_NAME_REGEX_FOR_GO);

private static final Logger log = LoggerFactory.getLogger(ProgrammingExerciseService.class);

Expand Down Expand Up @@ -434,12 +443,12 @@ private void validatePackageName(ProgrammingExercise programmingExercise, Progra
}

// Check if package name matches regex
Matcher packageNameMatcher;
switch (programmingExercise.getProgrammingLanguage()) {
case JAVA, KOTLIN -> packageNameMatcher = packageNamePattern.matcher(programmingExercise.getPackageName());
case SWIFT -> packageNameMatcher = packageNamePatternForSwift.matcher(programmingExercise.getPackageName());
Matcher packageNameMatcher = switch (programmingExercise.getProgrammingLanguage()) {
case JAVA, KOTLIN -> PACKAGE_NAME_PATTERN_FOR_JAVA_KOTLIN.matcher(programmingExercise.getPackageName());
case SWIFT -> PACKAGE_NAME_PATTERN_FOR_SWIFT.matcher(programmingExercise.getPackageName());
case GO -> PACKAGE_NAME_PATTERN_FOR_GO.matcher(programmingExercise.getPackageName());
default -> throw new IllegalArgumentException("Programming language not supported");
}
};
if (!packageNameMatcher.matches()) {
throw new BadRequestAlertException("The package name is invalid", "Exercise", "packagenameInvalid");
}
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, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP -> defaultRepositoryUpgradeService;
case SQL, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + programmingLanguage);
case KOTLIN, PYTHON, C, HASKELL, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP, GO -> defaultRepositoryUpgradeService;
case SQL, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + programmingLanguage);
};
}
}
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, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP -> "assignment";
case SQL, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + language);
case JAVA, PYTHON, C, HASKELL, KOTLIN, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP, GO -> "assignment";
case SQL, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + language);
};
}
},
Expand All @@ -230,8 +230,8 @@ public String forProgrammingLanguage(ProgrammingLanguage language) {
public String forProgrammingLanguage(ProgrammingLanguage language) {
return switch (language) {
case JAVA, PYTHON, HASKELL, KOTLIN, SWIFT, EMPTY, RUST, JAVASCRIPT, R, C_PLUS_PLUS, TYPESCRIPT -> "";
case C, VHDL, ASSEMBLER, OCAML, C_SHARP -> "tests";
case SQL, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + language);
case C, VHDL, ASSEMBLER, OCAML, C_SHARP, GO -> "tests";
case SQL, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + language);
};
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.C_PLUS_PLUS;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.C_SHARP;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.EMPTY;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.GO;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.HASKELL;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVA;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVASCRIPT;
Expand Down Expand Up @@ -40,6 +41,7 @@ public JenkinsProgrammingLanguageFeatureService() {
programmingLanguageFeatures.put(C, new ProgrammingLanguageFeature(C, false, false, true, false, false, List.of(FACT, GCC), false, false));
programmingLanguageFeatures.put(C_PLUS_PLUS, new ProgrammingLanguageFeature(C_PLUS_PLUS, false, false, true, false, false, List.of(), false, false));
programmingLanguageFeatures.put(C_SHARP, new ProgrammingLanguageFeature(C_SHARP, false, false, true, false, false, List.of(), false, false));
programmingLanguageFeatures.put(GO, new ProgrammingLanguageFeature(GO, false, false, true, true, false, List.of(), false, false));
programmingLanguageFeatures.put(HASKELL, new ProgrammingLanguageFeature(HASKELL, false, false, false, false, true, List.of(), false, false));
programmingLanguageFeatures.put(JAVA,
new ProgrammingLanguageFeature(JAVA, true, true, true, true, false, List.of(PLAIN_GRADLE, GRADLE_GRADLE, PLAIN_MAVEN, MAVEN_MAVEN, MAVEN_BLACKBOX), true, false));
Expand Down
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, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP -> jenkinsBuildPlanCreator;
case VHDL, ASSEMBLER, OCAML, SQL, GO, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
case JAVA, KOTLIN, PYTHON, C, HASKELL, SWIFT, EMPTY, RUST, JAVASCRIPT, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP, GO -> jenkinsBuildPlanCreator;
case VHDL, ASSEMBLER, OCAML, SQL, MATLAB, BASH, RUBY, POWERSHELL, ADA, DART, PHP ->
throw new UnsupportedOperationException(programmingLanguage + " templates are not available for Jenkins.");
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.C_PLUS_PLUS;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.C_SHARP;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.EMPTY;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.GO;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.HASKELL;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVA;
import static de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage.JAVASCRIPT;
Expand Down Expand Up @@ -47,6 +48,7 @@ public LocalCIProgrammingLanguageFeatureService() {
programmingLanguageFeatures.put(C, new ProgrammingLanguageFeature(C, false, true, true, false, false, List.of(FACT, GCC), false, true));
programmingLanguageFeatures.put(C_PLUS_PLUS, new ProgrammingLanguageFeature(C_PLUS_PLUS, false, false, true, false, false, List.of(), false, true));
programmingLanguageFeatures.put(C_SHARP, new ProgrammingLanguageFeature(C_SHARP, false, false, true, false, false, List.of(), false, true));
programmingLanguageFeatures.put(GO, new ProgrammingLanguageFeature(GO, false, false, true, true, false, List.of(), false, true));
programmingLanguageFeatures.put(HASKELL, new ProgrammingLanguageFeature(HASKELL, true, false, false, false, true, List.of(), false, true));
programmingLanguageFeatures.put(JAVA,
new ProgrammingLanguageFeature(JAVA, true, true, true, true, false, List.of(PLAIN_GRADLE, GRADLE_GRADLE, PLAIN_MAVEN, MAVEN_MAVEN), false, true));
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ artemis:
default: "ghcr.io/ls1intum/artemis-csharp-docker:v1.0.0"
typescript:
default: "ghcr.io/ls1intum/artemis-javascript-docker:v1.0.0"
go:
default: "ghcr.io/ls1intum/artemis-go-docker:v1.0.0"

# The following properties are used to configure the Artemis build agent.
# The build agent is responsible for executing the buildJob to test student submissions.
Expand Down
30 changes: 30 additions & 0 deletions src/main/resources/templates/aeolus/go/default.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -e
export AEOLUS_INITIAL_DIRECTORY=${PWD}
build () {
echo '⚙️ executing build'
cd "${testWorkingDirectory}"
go test -c -o /dev/null ./...

}

test () {
echo '⚙️ executing test'
cd "${testWorkingDirectory}"
go test ./... -json 2>&1 | go-junit-report -parser gojson -out test-results.xml
magaupp marked this conversation as resolved.
Show resolved Hide resolved
magaupp marked this conversation as resolved.
Show resolved Hide resolved

}

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

main "${@}"
17 changes: 17 additions & 0 deletions src/main/resources/templates/aeolus/go/default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
api: v0.0.1
metadata:
name: "Go"
id: Go
actions:
- name: build
script: |
cd "${testWorkingDirectory}"
go test -c -o /dev/null ./...
- name: test
script: |
cd "${testWorkingDirectory}"
go test ./... -json 2>&1 | go-junit-report -parser gojson -out test-results.xml
results:
- name: Go Test Results
path: "${testWorkingDirectory}/test-results.xml"
type: junit
7 changes: 7 additions & 0 deletions src/main/resources/templates/go/exercise/bubblesort.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ${packageName}

type BubbleSort struct{}
magaupp marked this conversation as resolved.
Show resolved Hide resolved

func NewBubbleSort() *BubbleSort {
panic("not implemented")
}
Loading
Loading