Skip to content

Commit

Permalink
Merge pull request #471 from JoyOfCodingPDX/issue-452/harvest-student…
Browse files Browse the repository at this point in the history
…-github-id

Address #452 by having the Survey program harvest the student's GitHub user name from the git config file. The user name is stored in the student's XML file.
  • Loading branch information
DavidWhitlock authored May 31, 2024
2 parents 8a07965 + 7e50b03 commit 2c4f733
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import java.util.regex.Pattern;

public class GitConfigParser {
static final Pattern PROPERTY_PATTERN = Pattern.compile(" {8}(.*) = (.*)");
static final Pattern PROPERTY_PATTERN = Pattern.compile("\\s+(.*) = (.*)");
static final Pattern REMOTE_PATTERN = Pattern.compile("\\[remote \"(.*)\"]");
private final Reader reader;
private String currentSection;

Expand Down Expand Up @@ -51,8 +52,7 @@ private void startCoreSection(Callback callback) {
}

private void startRemoteSection(String line, Callback callback) {
Pattern pattern = Pattern.compile("\\[remote \"(.*)\"]");
Matcher matcher = pattern.matcher(line);
Matcher matcher = REMOTE_PATTERN.matcher(line);
if (!matcher.matches()) {
throw new IllegalStateException("Cannot parse line with remote: \"" + line + "\"");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package edu.pdx.cs.joy.grader;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GitHubUserNameFinder implements GitConfigParser.Callback {
private String gitHubUserName;
private boolean isInOrigin;

@Override
public void startCoreSection() {

}

@Override
public void property(String name, String value) {
if (name.equals("url") && this.isInOrigin) {
extractGitHubUserNameFrom(value);
}
}

private void extractGitHubUserNameFrom(String gitUrl) {
Pattern pattern = Pattern.compile("git@github.com:(.*)/.*\\.git");
Matcher matcher = pattern.matcher(gitUrl);
if (matcher.matches()) {
this.gitHubUserName = matcher.group(1);
}
}

@Override
public void endSection(String name) {
this.isInOrigin = false;
}

@Override
public void startRemoteSection(String name) {
if (name.equals("origin")) {
this.isInOrigin = true;
}
}

public String getGitHubUserName() {
return gitHubUserName;
}
}
39 changes: 36 additions & 3 deletions grader/src/main/java/edu/pdx/cs/joy/grader/Survey.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ public class Survey extends EmailSender {

private boolean sendEmail = true;
private final File xmlFileDir;
private File gitCheckoutDir;

public Survey(PrintStream out, PrintStream err, InputStream in, File xmlFileDir) {
public Survey(PrintStream out, PrintStream err, InputStream in, File xmlFileDir, File gitCheckoutDir) {
this.out = new PrintWriter(out, true);
this.err = new PrintWriter(err, true);
this.in = new BufferedReader(new InputStreamReader(in));
this.xmlFileDir = xmlFileDir;
this.gitCheckoutDir = gitCheckoutDir;
}

/**
Expand All @@ -52,6 +54,9 @@ private String getSummary(Student student) {
sb.append("Major: ").append(student.getMajor()).append("\n");
}
sb.append("Enrolled in: ").append(student.getEnrolledSection().asString()).append("\n");
if (student.getGitHubUserName() != null) {
sb.append("GitHub User Name: ").append(student.getGitHubUserName()).append("\n");
}
return sb.toString();
}

Expand Down Expand Up @@ -87,7 +92,8 @@ private void usage() {
}

public static void main(String[] args) {
Survey survey = new Survey(System.out, System.err, System.in, new File(System.getProperty("user.dir")));
File currentDirectory = new File(System.getProperty("user.dir"));
Survey survey = new Survey(System.out, System.err, System.in, currentDirectory, currentDirectory);
survey.takeSurvey(args);
}

Expand Down Expand Up @@ -146,10 +152,37 @@ private Student gatherStudentInformation() {
askQuestionAndSetValue("What is your major?", student::setMajor);

askEnrolledSectionQuestion(student);
askGitHubUserNameQuestion(student);

return student;
}

private void askGitHubUserNameQuestion(Student student) {
String gitHubUserName = findGitHubUserName();
String okay = ask("Is it okay to record your GitHub username of \"" + gitHubUserName
+ "\" so you can be added to the shared GitHub repo for Pair/Mob Programming? [y/n]");
if (okay.equalsIgnoreCase("y")) {
student.setGitHubUserName(gitHubUserName);
}
}

private String findGitHubUserName() {
File dotGit = new File(this.gitCheckoutDir, ".git");
File config = new File(dotGit, "config");
if (config.isFile()) {
try {
GitConfigParser parser = new GitConfigParser(new FileReader(config));
GitHubUserNameFinder finder = new GitHubUserNameFinder();
parser.parse(finder);
return finder.getGitHubUserName();

} catch (IOException e) {
return null;
}
}
return null;
}

@VisibleForTesting
static boolean isEmailAddress(String id) {
try {
Expand Down Expand Up @@ -364,7 +397,7 @@ private String verifyInformation(Student student) {
"yourself:\n");
out.println(summary);

String verify = ask("\nIs this information correct (y/n)?");
String verify = ask("\nIs this information correct? [y/n]");
if (!verify.equals("y")) {
printErrorMessageAndExit("** Not sending information. Exiting.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class Student extends NotableImpl {
private List<String> resubmitted; // Names of resubmitted Assignments
private String canvasId;
private Section enrolledSection;
private String gitHubUserName;

/////////////////////// Constructors ///////////////////////

Expand Down Expand Up @@ -531,6 +532,14 @@ public Section getEnrolledSection() {
return enrolledSection;
}

public String getGitHubUserName() {
return gitHubUserName;
}

public void setGitHubUserName(String gitHubUserName) {
this.gitHubUserName = gitHubUserName;
}

public enum Section {
UNDERGRADUATE("undergraduate"), GRADUATE("graduate");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ private static void appendStudentInformation(Student student, Element root) {
appendTextElementIfValueIsNotNull(root, "email", student.getEmail());
appendTextElementIfValueIsNotNull(root, "major", student.getMajor());
appendTextElementIfValueIsNotNull(root, "canvas-id", student.getCanvasId());
appendTextElementIfValueIsNotNull(root, "github-user-name", String.valueOf(student.getGitHubUserName()));
appendTextElementIfValueIsNotNull(root, "letter-grade", Objects.toString(student.getLetterGrade(), null));

setAttributeIfValueIsNotNull(root, "enrolled-section", getSectionXmlAttributeValue(student.getEnrolledSection()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
public class XmlStudentParser extends XmlHelper {

/** The Reader from which the XML Data is read */
private Reader reader;
private final Reader reader;

/////////////////////// Constructors ////////////////////////

Expand Down Expand Up @@ -207,6 +207,10 @@ public Student parseStudent() throws ParserException {
String canvasId = extractTextFrom(child);
student.setCanvasId(canvasId);

} else if (child.getTagName().equals("github-user-name")) {
String gitHubUserName = extractTextFrom(child);
student.setGitHubUserName(gitHubUserName);

} else if (child.getTagName().equals("letter-grade")) {
String letterGrade = extractTextFrom(child);
student.setLetterGrade(LetterGrade.fromString(letterGrade));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ points it is worth, a type, a due date, and some optional notes -->
address, social security number, a major, some grades, some late
assignments, and some notes -->
<!ELEMENT student (id, firstName?, lastName?, nickName?, email?, ssn?,
major?, canvas-id?, d2l-id?, letter-grade?, grades?, late?, resubmitted?, notes?)>
major?, canvas-id?, github-user-name?, d2l-id?, letter-grade?, grades?, late?, resubmitted?, notes?)>
<!ATTLIST student
enrolled-section (undergraduate | graduate) #IMPLIED
>
Expand All @@ -76,6 +76,7 @@ assignments, and some notes -->
<!ELEMENT ssn (#PCDATA)> <!-- xxx-xx-xxxx -->
<!ELEMENT major (#PCDATA)>
<!ELEMENT canvas-id (#PCDATA)>
<!ELEMENT github-user-name (#PCDATA)>
<!ELEMENT d2l-id (#PCDATA)>
<!ELEMENT letter-grade (#PCDATA)>
<!ELEMENT grades (grade*)>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package edu.pdx.cs.joy.grader;

import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;

public class GitHubUserNameFinderTest {

@Test
void findGitHubUserName() {
GitHubUserNameFinder finder = new GitHubUserNameFinder();
finder.startRemoteSection("origin");
finder.property("url", "git@github.com:JoyOfCodingPDX/JoyOfCoding.git");

assertThat(finder.getGitHubUserName(), equalTo("JoyOfCodingPDX"));
}
}
43 changes: 40 additions & 3 deletions grader/src/test/java/edu/pdx/cs/joy/grader/SurveyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.junit.jupiter.api.io.TempDir;

import java.io.*;
import java.nio.file.Files;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
Expand Down Expand Up @@ -88,15 +89,23 @@ void successfulSurveyWritesStudentXmlFile(@TempDir File tempDir) throws IOExcept
String email = "email@email.com";
String major = "Major";
String section = "u";
String recordGitHubUserName = "y";
String learn = "A lot";
String anythingElse = "Nope";
String verify = "y";

InputStream in = getInputStreamWithLinesOfText(firstName, lastName, nickName, loginId, email, major, section, learn, anythingElse, verify);
String gitHubUserName = "GitHubUserName";

Survey survey = new Survey(new TextCapturingOutputStream().getPrintStream(), new TextCapturingOutputStream().getPrintStream(), in, tempDir);
InputStream in = getInputStreamWithLinesOfText(firstName, lastName, nickName, loginId, email, major, section, recordGitHubUserName, learn, anythingElse, verify);
createGitConfigWithUserName(tempDir, gitHubUserName);

TextCapturingOutputStream stdOut = new TextCapturingOutputStream();
Survey survey = new Survey(stdOut.getPrintStream(), new TextCapturingOutputStream().getPrintStream(), in, tempDir, tempDir);
survey.takeSurvey("-noEmail");

String writtenToStdOut = stdOut.getTextThatWasOutput();
assertThat(writtenToStdOut, containsString("GitHub User Name: " + gitHubUserName));

File xmlFile = new File(tempDir, Survey.STUDENT_XML_FILE_NAME);
XmlStudentParser parser = new XmlStudentParser(xmlFile);
Student student = parser.parseStudent();
Expand All @@ -108,6 +117,30 @@ void successfulSurveyWritesStudentXmlFile(@TempDir File tempDir) throws IOExcept
assertThat(student.getEmail(), equalTo(email));
assertThat(student.getMajor(), equalTo(major));
assertThat(student.getEnrolledSection(), equalTo(Student.Section.UNDERGRADUATE));
assertThat(student.getGitHubUserName(), equalTo(gitHubUserName));
}

private void createGitConfigWithUserName(File tempDir, String gitHubUserName) throws IOException {
File dotGit = new File(tempDir, ".git");
assertThat(dotGit.mkdir(), is(true));
File config = new File(dotGit, "config");

try (PrintWriter pw = new PrintWriter(new FileWriter(config))) {
pw.println("[core]\n" +
"\trepositoryformatversion = 0\n" +
"\tfilemode = true\n" +
"\tbare = false\n" +
"\tlogallrefupdates = true\n" +
"\tignorecase = true\n" +
"\tprecomposeunicode = true\n" +
"[remote \"origin\"]\n" +
"\turl = git@github.com:" + gitHubUserName + "/JoyOfCoding.git\n" +
"\tfetch = +refs/heads/*:refs/remotes/origin/*\n" +
"[branch \"main\"]\n" +
"\tremote = origin\n" +
"\tmerge = refs/heads/main\n");
pw.flush();
}
}

private InputStream getInputStreamWithLinesOfText(String... lines) {
Expand All @@ -121,10 +154,14 @@ private InputStream getInputStreamWithLinesOfText(String... lines) {
}

private static class TextCapturingOutputStream {
private final OutputStream captured = new ByteArrayOutputStream();
private final ByteArrayOutputStream captured = new ByteArrayOutputStream();

public PrintStream getPrintStream() {
return new PrintStream(captured);
}

String getTextThatWasOutput() {
return captured.toString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,15 @@ void canParseOldXmlFileWithD2LId() throws ParserException {
assertThat(student.getCanvasId(), nullValue());
}

@Test
void gitHubUserNameIsPersisted() throws ParserException, TransformerException {
String gitHubUserName = "gitHubUserName";
Student student = new Student("studentId");
student.setGitHubUserName(gitHubUserName);

Student student2 = writeAndReadStudentAsXml(student);

assertThat(student2.getGitHubUserName(), equalTo(gitHubUserName));
}

}
47 changes: 25 additions & 22 deletions grader/src/test/resources/edu/pdx/cs/joy/grader/gitConfig.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:JoyOfCodingPDX/JoyOfCoding.git
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@github.com:JoyOfCodingPDX/JoyOfCoding.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
remote = origin
merge = refs/heads/main
[branch "issue-463/use-LocalDateTime-for-projects"]
remote = origin
merge = refs/heads/issue-463/use-LocalDateTime-for-projects
remote = origin
merge = refs/heads/issue-463/use-LocalDateTime-for-projects
[branch "issue-453/use-newer-github-actions"]
remote = origin
merge = refs/heads/issue-453/use-newer-github-actions
remote = origin
merge = refs/heads/issue-453/use-newer-github-actions
[branch "issue-463/move-snapshot-repository-include-to-top-level-pom"]
remote = origin
merge = refs/heads/issue-463/move-snapshot-repository-include-to-top-level-pom
remote = origin
merge = refs/heads/issue-463/move-snapshot-repository-include-to-top-level-pom
[branch "issue-465/java-22"]
remote = origin
merge = refs/heads/issue-465/java-22
remote = origin
merge = refs/heads/issue-465/java-22
[branch "issue-454/http-code-in-stack-trace"]
remote = origin
merge = refs/heads/issue-454/http-code-in-stack-trace
remote = origin
merge = refs/heads/issue-454/http-code-in-stack-trace
[branch "1.1.1-SNAPSHOT"]
remote = origin
merge = refs/heads/1.1.1-SNAPSHOT
remote = origin
merge = refs/heads/1.1.1-SNAPSHOT
[branch "issue-452/harvest-student-github-id"]
remote = origin
merge = refs/heads/issue-452/harvest-student-github-id

0 comments on commit 2c4f733

Please sign in to comment.