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

Issue 452 harvest student GitHub user name from git config file #471

Merged
merged 5 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
Loading