exclude: true --- class: title_bg .title[ ghclass ] .subtitle[ an R package for managing classes with GitHub ] .conference[ .name[ JSM 2019 · Denver ] .bitly[ [bit.ly/JSM2019_ghclass](http://bit.ly/JSM2019_ghclass) ] ] .author[ .name[ Colin Rundel ] .school[ Univ of Edinburgh · Duke Univ ] ] --- ## Reproducible Assignments **Goals**: * Teach (enforce) version control and reproducible workflows * Encourage (enforce) collaboration * Embrace modern tools and methods -- <br/> **Organization**: * Core toolkit: R + RStudio + RMarkdown * Spend 1 lecture on git / GitHub * GitHub setup: * 1 organization / course * 1 repo / (team | student) / assignment * Randomly assigned teams of 3-4 students / assignment --- ## Setup 1. .sep[ Signup for a GitHub Account [github.com]() ] 2. .sep[ Get a GitHub personal access token (PAT) [github.com/settings/tokens](https://github.com/settings/tokens) ] 3. .sep[ Setup git and GitHub access in R [`usethis` setup vignette](https://usethis.r-lib.org/articles/articles/usethis-setup.html) & <br/> [happy git with R](https://happygitwithr.com/) ] 3. .sep[ Signup for GitHub Education [education.github.com/benefits](https://education.github.com/benefits) ] 4. .sep[ Create a GitHub Organization for your class [github.com/organizations/new](https://github.com/organizations/new) ] <br/> .center[ Only **Step 5** needs to be repeated for a new class! ] --- ## Introduction to `ghclass` ```r devtools::install_github("rundel/ghclass") library(ghclass) ``` -- <br/> Some design principals behind this package: 1. Functions are prefixed with `org`, `repo`, `team`, `github` or `local_repo` to indicate what they operate on. 2. Functions are vectorized over their parameters (batch related operations). 3. Be verbose about what is happening, report failures but don't halt execution. 4. Most actions are non-destructive (backed by git), the handful of dangerous operations will warn you. 5. Follow the unix design philosophy, work towards simple & composable functions --- ## Org & Roster We will be using [ghclass-demo](https://github.com/ghclass-demo) as our class organization, hopefully your Org has a slightly more informative name . -- .center[ (I find `course#`-`semester` works well, e.g. `Sta323-Sp19`). ] -- <br/><br/> ```r (roster = readr::read_csv("files/roster.csv")) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #949494;'># A tibble: 6 x 4</span><span> ## netid email github hw01 ## </span><span style='color: #949494;font-style: italic;'><chr></span><span> </span><span style='color: #949494;font-style: italic;'><chr></span><span> </span><span style='color: #949494;font-style: italic;'><chr></span><span> </span><span style='color: #949494;font-style: italic;'><chr></span><span> ## </span><span style='color: #BCBCBC;'>1</span><span> za17 anya@school.edu ghclass-anya hw01-team01 ## </span><span style='color: #BCBCBC;'>2</span><span> kb34 bruno@school.edu ghclass-bruno hw01-team01 ## </span><span style='color: #BCBCBC;'>3</span><span> ac13 celine@school.edu ghclass-celine hw01-team02 ## </span><span style='color: #BCBCBC;'>4</span><span> bd88 diego@school.edu ghclass-diego hw01-team02 ## </span><span style='color: #BCBCBC;'>5</span><span> se01 elijah@school.edu ghclass-elijah hw01-team03 ## </span><span style='color: #BCBCBC;'>6</span><span> df00 francis@school.edu ghclass-francis hw01-team03 </span></CODE></PRE> --- background-image: url("imgs/01_github_empty.png") background-position: center background-size: contain --- ## Checking your git / GitHub config ```r github_test_token() ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Your github token is functioning correctly. </span></CODE></PRE> -- ```r usethis::git_sitrep() ``` <PRE class="fansi fansi-output"><CODE>## <span style='font-weight: bold;'>Git user</span><span> ## * Name: </span><span style='color: #0000BB;'>'Colin Rundel'</span><span> ## * Email: </span><span style='color: #0000BB;'>'rundel@gmail.com'</span><span> ## * Vaccinated: </span><span style='color: #0000BB;'>TRUE</span><span> ## </span><span style='font-weight: bold;'>usethis + git2r</span><span> ## * Default usethis protocol: </span><span style='color: #555555;'><unset></span><span> ## * git2r supports SSH: </span><span style='color: #0000BB;'>TRUE</span><span> ## * Credentials: </span><span style='color: #0000BB;'>'<user-provided git2r credential object with class cred_ssh_key>'</span><span> ## </span><span style='font-weight: bold;'>GitHub</span><span> ## * Personal access token: </span><span style='color: #0000BB;'>'<found in env var>'</span><span> ## * User: </span><span style='color: #0000BB;'>'rundel'</span><span> ## * Name: </span><span style='color: #0000BB;'>'Colin Rundel'</span><span> ## </span><span style='font-weight: bold;'>Repo</span><span> ## * Path: </span><span style='color: #0000BB;'>'/Users/rundel/Desktop/Presentations/.git'</span><span> ## * Local branch -> remote tracking branch: </span><span style='color: #0000BB;'>'master'</span><span> -> </span><span style='color: #0000BB;'>'origin/master'</span><span> ## </span><span style='font-weight: bold;'>GitHub pull request readiness</span><span> ## * origin: </span><span style='color: #0000BB;'>rundel/Presentations</span><span>, </span><span style='color: #0000BB;'>can push</span><span> ## * upstream: </span><span style='color: #0000BB;'>'<no such remote>'</span><span> </span></CODE></PRE> --- ## Inviting Students ```r org_invite(org = "ghclass-demo", user = roster$github) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Invited user </span><span style='color: #0000BB;'>'ghclass-anya'</span><span> to org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Invited user </span><span style='color: #0000BB;'>'ghclass-bruno'</span><span> to org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Invited user </span><span style='color: #0000BB;'>'ghclass-celine'</span><span> to org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Invited user </span><span style='color: #0000BB;'>'ghclass-diego'</span><span> to org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Invited user </span><span style='color: #0000BB;'>'ghclass-elijah'</span><span> to org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Invited user </span><span style='color: #0000BB;'>'ghclass-francis'</span><span> to org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. </span></CODE></PRE> -- ```r org_members("ghclass-demo", include_admins = FALSE) ``` ``` ## character(0) ``` ```r org_pending_members("ghclass-demo") ``` ``` ## [1] "ghclass-anya" "ghclass-bruno" "ghclass-diego" "ghclass-elijah" ## [5] "ghclass-francis" "ghclass-celine" ``` --- background-image: url("imgs/02_github_members.png") background-position: center background-size: contain --- background-image: url("imgs/03_github_pending.png") background-position: center background-size: contain --- ## A few days later ... ```r org_members("ghclass-demo", include_admins = FALSE) ``` ``` ## [1] "ghclass-anya" "ghclass-bruno" "ghclass-celine" "ghclass-diego" ``` ```r org_pending_members("ghclass-demo") ``` ``` ## [1] "ghclass-elijah" "ghclass-francis" ``` -- <br/> ## several emails and a week later ... ```r org_members("ghclass-demo", include_admins = FALSE) ``` ``` ## [1] "ghclass-anya" "ghclass-bruno" "ghclass-celine" "ghclass-diego" ## [5] "ghclass-elijah" "ghclass-francis" ``` ```r org_pending_members("ghclass-demo") ``` ``` ## character(0) ``` --- background-image: url("imgs/04_github_accepted.png") background-position: center background-size: contain --- ## Team Assignment ```r org_create_assignment(org = "ghclass-demo", repo = roster$hw01, user = roster$github, team = roster$hw01, source_repo = "Sta323-Sp19/hw1") ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created team </span><span style='color: #0000BB;'>'hw01-team01'</span><span> in org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created team </span><span style='color: #0000BB;'>'hw01-team02'</span><span> in org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created team </span><span style='color: #0000BB;'>'hw01-team03'</span><span> in org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-anya'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-bruno'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-celine'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-diego'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-elijah'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-francis'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added team </span><span style='color: #0000BB;'>'hw01-team01'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added team </span><span style='color: #0000BB;'>'hw01-team02'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added team </span><span style='color: #0000BB;'>'hw01-team03'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'Sta323-Sp19/hw1'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Removed local copy of </span><span style='color: #0000BB;'>'Sta323-Sp19/hw1'</span><span> </span></CODE></PRE> --- background-image: url("imgs/05_github_hw01_repos.png") background-position: center background-size: contain --- .smaller[ ```r team_create("ghclass-demo", team = roster$hw01) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Created team </span><span style='color: #0000BB;'>'hw01-team01'</span><span> in org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created team </span><span style='color: #0000BB;'>'hw01-team02'</span><span> in org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created team </span><span style='color: #0000BB;'>'hw01-team03'</span><span> in org </span><span style='color: #0000BB;'>'ghclass-demo'</span><span>. </span></CODE></PRE> ```r team_invite("ghclass-demo", user = roster$github, team = roster$hw01) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-anya'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-bruno'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-celine'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-diego'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-elijah'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added </span><span style='color: #0000BB;'>'ghclass-francis'</span><span> to team </span><span style='color: #0000BB;'>'hw01-team03'</span><span>. </span></CODE></PRE> ```r repo_create("ghclass-demo", name = roster$hw01) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. </span></CODE></PRE> ```r repo_add_team(repo = org_repos("ghclass-demo", filter = "hw01-"), team = org_teams("ghclass-demo", filter = "hw01-")) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Added team </span><span style='color: #0000BB;'>'hw01-team01'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added team </span><span style='color: #0000BB;'>'hw01-team02'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added team </span><span style='color: #0000BB;'>'hw01-team03'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. </span></CODE></PRE> ```r repo_mirror(source_repo = "Sta323-Sp19/hw1", target_repo = org_repos("ghclass-demo", filter = "hw01-")) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'Sta323-Sp19/hw1'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'hw1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Removed local copy of </span><span style='color: #0000BB;'>'Sta323-Sp19/hw1'</span><span> </span></CODE></PRE> ] --- ## Individual Assignment ```r org_create_assignment(org = "ghclass-demo", repo = paste0("mid1-", roster$github), user = roster$github, source_repo = "Sta323-Sp19/midterm1") ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-anya'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-bruno'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-celine'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-diego'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-elijah'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-francis'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added user </span><span style='color: #0000BB;'>'ghclass-anya'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-anya'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added user </span><span style='color: #0000BB;'>'ghclass-bruno'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-bruno'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added user </span><span style='color: #0000BB;'>'ghclass-celine'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-celine'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added user </span><span style='color: #0000BB;'>'ghclass-diego'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-diego'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added user </span><span style='color: #0000BB;'>'ghclass-elijah'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-elijah'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added user </span><span style='color: #0000BB;'>'ghclass-francis'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-francis'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'Sta323-Sp19/midterm1'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'midterm1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-anya'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'midterm1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-bruno'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'midterm1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-celine'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'midterm1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-diego'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'midterm1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-elijah'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Pushed (mirror) </span><span style='color: #0000BB;'>'midterm1'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-francis'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Removed local copy of </span><span style='color: #0000BB;'>'Sta323-Sp19/midterm1'</span><span> </span></CODE></PRE> --- background-image: url("imgs/06_github_mid1_repos.png") background-position: center background-size: contain --- ## What about GitHub Classroom? <img src="imgs/classroom.png" width="100%" style="display: block; margin: auto;" /> --- ## Making Changes ```r repo_add_file(repo = org_repos("ghclass-demo", "hw01-"), file = "files/fizzbuzz.png") ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #BB0000;'>✖</span><span> Failed to add file </span><span style='color: #0000BB;'>'fizzbuzz.png'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>: already exists. ## If you want to force-add this file, re-run the command with </span><span style='color: #555555;'>`overwrite = TRUE`</span><span>. ## </span><span style='color: #BB0000;'>✖</span><span> Failed to add file </span><span style='color: #0000BB;'>'fizzbuzz.png'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>: already exists. ## If you want to force-add this file, re-run the command with </span><span style='color: #555555;'>`overwrite = TRUE`</span><span>. ## </span><span style='color: #BB0000;'>✖</span><span> Failed to add file </span><span style='color: #0000BB;'>'fizzbuzz.png'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>: already exists. ## If you want to force-add this file, re-run the command with </span><span style='color: #555555;'>`overwrite = TRUE`</span><span>. </span></CODE></PRE> -- ```r repo_add_file(repo = org_repos("ghclass-demo", "hw01-"), file = "files/fizzbuzz.png", overwrite = TRUE) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Added file </span><span style='color: #0000BB;'>'fizzbuzz.png'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added file </span><span style='color: #0000BB;'>'fizzbuzz.png'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Added file </span><span style='color: #0000BB;'>'fizzbuzz.png'</span><span> to repo </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03'</span><span>. </span></CODE></PRE> --- background-image: url("imgs/10_github_readme1.png") background-position: center background-size: contain --- ## Modify a file ```r repo_modify_file(repo = org_repos("ghclass-demo", "hw01-"), file = "README.md", pattern = "on Thursday 1/24/2019.", content = "on Wednesday 10/07/2019.") ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Modified file </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01/README.md'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Modified file </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team02/README.md'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Modified file </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team03/README.md'</span><span>. </span></CODE></PRE> -- <img src="imgs/12_github_readme3.png" width="75%" style="display: block; margin: auto;" /> --- ## Collect student work ```r local_repo_clone(repo = org_repos("ghclass-demo", "mid1-"), local_path = "mid1") ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-anya'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-bruno'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-celine'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-diego'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-elijah'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/mid1-ghclass-francis'</span><span>. </span></CODE></PRE> -- <img src="imgs/13_github_clone.png" width="65%" style="display: block; margin: auto;" /> --- ## Organize student work ```r local_repo_rename(repo_dir = "mid1", pattern = roster$github, replacement = paste0(roster$netid, "-(\\1)")) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Renaming </span><span style='color: #0000BB;'>'mid1/mid1-ghclass-anya'</span><span> to </span><span style='color: #0000BB;'>'mid1/mid1-za17-(ghclass-anya)'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Renaming </span><span style='color: #0000BB;'>'mid1/mid1-ghclass-bruno'</span><span> to </span><span style='color: #0000BB;'>'mid1/mid1-kb34-(ghclass-bruno)'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Renaming </span><span style='color: #0000BB;'>'mid1/mid1-ghclass-celine'</span><span> to </span><span style='color: #0000BB;'>'mid1/mid1-ac13-(ghclass-celine)'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Renaming </span><span style='color: #0000BB;'>'mid1/mid1-ghclass-diego'</span><span> to </span><span style='color: #0000BB;'>'mid1/mid1-bd88-(ghclass-diego)'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Renaming </span><span style='color: #0000BB;'>'mid1/mid1-ghclass-elijah'</span><span> to </span><span style='color: #0000BB;'>'mid1/mid1-se01-(ghclass-elijah)'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Renaming </span><span style='color: #0000BB;'>'mid1/mid1-ghclass-francis'</span><span> to </span><span style='color: #0000BB;'>'mid1/mid1-df00-(ghclass-francis)'</span><span>. </span></CODE></PRE> -- <img src="imgs/14_local_rename.png" width="65%" style="display: block; margin: auto;" /> --- ## Feedback? ```r repo_style("ghclass-demo/hw01-team01", files = "*.Rmd", draft = TRUE) ``` <PRE class="fansi fansi-output"><CODE>## <span style='color: #00BB00;'>✔</span><span> Created branch </span><span style='color: #0000BB;'>'styler'</span><span> from </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Cloned </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01@styler'</span><span>. ## </span><span style='color: #00BB00;'>✔</span><span> Created pull request for </span><span style='color: #0000BB;'>'ghclass-demo/hw01-team01 (master <= styler)'</span><span>. </span></CODE></PRE> -- <img src="imgs/15_github_pull_req.png" width="60%" style="display: block; margin: auto;" /> --- background-image: url("imgs/16_github_diff.png") background-position: center background-size: contain --- ## Future Work * We will be submitting to CRAN in the next month * Active summer project adding functionality for peer review by Mine Cetinkaya-Rundel and Therese Anders * Support for GitHub actions for automated feedback ([rundel/wercker](https://github.com/rundel/wercker) replacement) * Support more workflows, if you use a GitHub based workflow for teaching that was not reflected here please get in touch. --- # Thank you! .middle[ .center[ <div style="width: 98%"> <table class="contact" style="text-align: left; font-size: 120%; margin-left:auto; margin-right:auto; width:50%;"> <tbody> <tr> <td style="vertical-align: middle;"> <i class="far fa-file-powerpoint fa-fw fa-2x"></i> </td> <td> <a href="http://bit.ly/User2019_ghclass">bit.ly/JSM2019_ghclass</a> </td> </tr> <tr><td><br/></td></tr> <tr> <td style="vertical-align: middle;"> <i class="fas fa-box fa-fw fa-2x"></i> </td> <td> <a href="https://github.com/rundel/ghclass">rundel/ghclass</a> <br/> </td> </tr> <tr><td><br/></td></tr> <tr> <td style="vertical-align: middle;"> <i class="fas fa-map fa-fw fa-2x"></i> </td> <td> <a href="https://rundel.github.io/ghclass">rundel.github.io/ghclass</a> </td> </tr> <tr><td><br/></td></tr> <tr> <td style="vertical-align: middle;"> <i class="fab fa-github-square fa-fw fa-2x"></i> </td> <td> <a href="https://github.com/rundel">github.com/rundel</a> </td> </tr> <tr><td><br/></td></tr> <tr> <td style="vertical-align: middle;"> <i class="fas fa-envelope fa-fw fa-2x"></i> </td> <td> <a href="mailto:rundel@gmail.com">rundel@gmail.com</a> </td> </tr> <tr><td><br/></td></tr> <tr> <td style="vertical-align: middle;"> <i class="fab fa-twitter-square fa-fw fa-2x"></i> </td> <td> <a href="https://twitter.com/rundel">@rundel</a> </td> </tr> </tbody> </table> </div> ] ]