ma_salmon
maelle" />
class: center, middle, inverse, title-slide # Our package reviews in review! ## Introducing & analyzing rOpenSci onboarding ### Maëlle Salmon, editor at rOpensci onboarding
ma_salmon
maelle ### 2018/03/17 --- # Bonjour ! -- ```r library("magrittr") # my chibi made by Oz Locke! maelle <- magick::image_read("assets/happy_maelle.png") %>% magick::image_resize("100x100") magick::image_blank(500, 100, col = "salmon") %>% magick::image_composite(maelle, offset = "+0+0") %>% magick::image_annotate("Good morning! Goeie môre! Sanibonani! Molweni!", boxcolor = "white", location = "+100+25", size = 15) ``` <img src="slides_files/figure-html/unnamed-chunk-1-1.png" width="667" style="display: block; margin: auto;" /> --- # My place in the R community ```r row1 <- c(magick::image_read("assets/locke.png"), magick::image_read("assets/rweekly.png")) %>% magick::image_append() row2 <- c(magick::image_read("assets/ropensci.png"), magick::image_read("assets/rladies.png")) %>% magick::image_append() magick::image_blank(225, 200, col = "white") %>% magick::image_composite(row1, offset = "+0+100") %>% magick::image_composite(row2, offset = "+50+25") ``` <img src="slides_files/figure-html/unnamed-chunk-2-1.png" width="300" style="display: block; margin: auto;" /> --- # Nancy, France --- # Nancy, France: _La Place Stanislas_ ```r magick::image_read("assets/stan.JPG") %>% magick::image_resize("400x400") %>% magick::image_composite(maelle, offset = "+200+200") ``` <img src="slides_files/figure-html/unnamed-chunk-3-1.png" width="533" style="display: block; margin: auto;" /> --- # Nancy, France: _Le Parc de la Pépinière_ ```r magick::image_read("assets/pepiniere.JPG") %>% magick::image_resize("400x400") %>% magick::image_composite(maelle, offset = "+220+190") ``` <img src="slides_files/figure-html/unnamed-chunk-4-1.png" width="533" style="display: block; margin: auto;" /> --- # Nancy, France: _La Place Nelson Mandela_ ```r magick::image_read("assets/mandela.JPG") %>% magick::image_resize("400x400") ``` <img src="slides_files/figure-html/unnamed-chunk-5-1.png" width="533" style="display: block; margin: auto;" /> --- # What's rOpenSci? -- .font150[ * Community of researchers and software developpers * R packages for open and reproducible science * Community and staff contributions] --- # rOpenSci packages suite https://ropensci.org/packages/ -- <img src="slides_files/figure-html/unnamed-chunk-6-1.png" width="1100" style="display: block; margin: auto;" /> --- # rOpenSci packages suite https://ropensci.org/packages/ <img src="slides_files/figure-html/unnamed-chunk-7-1.png" width="1100" style="display: block; margin: auto;" /> --- # rOpenSci packages suite https://ropensci.org/packages/ <img src="slides_files/figure-html/unnamed-chunk-8-1.png" width="1100" style="display: block; margin: auto;" /> --- # rOpenSci onboarding! .font150[How to ensure quality in the whole suite?] -- .font150[Open software reviews.] -- * .font150[drive adoption of best practices and standards] -- * .font150[build a community of practice] -- * .font150[partnerships with the Journal of Open Source Software and Methods in Ecology and Evolution] --- # What to review for? -- ```r magick::image_read("https://raw.github.com/jtleek/rpackages/master/documentation.png") ``` <img src="slides_files/figure-html/unnamed-chunk-9-1.png" width="1152" style="display: block; margin: auto;" /> --- # Review criteria .font150[ * Open-source initiative (OSI) compatible license * Complete docs * High test coverage * Readable code * Usability] -- .font150[https://github.com/ropensci/onboarding/blob/master/packaging_guide.md] -- .font150[Soon as bookdown!] --- # How to review? * .font150[Open & non-adversarial] -- * .font150[No rejections] -- * .font150[Makes the process constructive for everyone involved] -- * .font150[Technically, using GitHub infrastructure] --- # How to show stuff on GitHub? -- ```r magick_webshot <- function(...){ webshot::webshot(...) webshot <- magick::image_read("webshot.png") file.remove("webshot.png") webshot } ``` --- # rOpenSci onboarding ```r magick_webshot(url = "https://github.com/ropensci/onboarding", selector = ".public", expand = c(92, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-11-1.png" width="1353" style="display: block; margin: auto;" /> --- # Let's login chibimaelle * .font150[`webshot` docs: "If you are familiar with JavaScript"] -- * .font150[Thanks Bea for coaching!] -- * .font150[Use the "return URL" instead of the URL] --- # Let's login chibimaelle ```r magick_webshot(url = "https://github.com/login?return_to=%2Fropensci%2Fonboarding") ``` <img src="slides_files/figure-html/unnamed-chunk-12-1.png" width="1323" style="display: block; margin: auto;" /> --- # Let's login chibimaelle ```r magick_webshot_login <- function(url, ...){ return_url <- stringr::str_replace(url, "github.com/", "github.com/login?return_to=%2F") load("pwd.RData") eval <- paste0("casper.then(function() { this.sendKeys('#login_field', 'chibimaelle'); this.sendKeys('#password', '",pwd,"'); this.click('.btn-block'); this.wait(50); });") magick_webshot(return_url, eval = eval, ...) } ``` -- * .font150[Only for my screenshots!] * .font150[GitHub APIs (Application Programming Interfaces) to interact with GitHub and its data] --- # rOpenSci onboarding, again! ```r magick_webshot_login("https://github.com/ropensci/onboarding", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-14-1.png" width="1353" style="display: block; margin: auto;" /> --- # The issues tracker ```r magick_webshot("https://github.com/ropensci/onboarding/issues", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-15-1.png" width="1353" style="display: block; margin: auto;" /> --- # Submitting a package ```r magick_webshot_login("https://github.com/AustralianAntarcticDivision/bowerbird", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-16-1.png" width="1336" style="display: block; margin: auto;" /> --- # Submitting a package ```r magick_webshot("https://github.com/ropensci/onboarding/issues", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-17-1.png" width="1353" style="display: block; margin: auto;" /> --- # Submitting a package ```r magick_webshot_login("https://github.com/ropensci/onboarding/issues/new", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-18-1.png" width="1353" style="display: block; margin: auto;" /> --- # Rejection .font150[No rejections... but out-of-scope packages not onboarded.] .font150[https://github.com/ropensci/onboarding/blob/master/policies.md] -- * .font150[fit in our categories: data retrieval, data extraction, database access, data munging, data deposition, reproducibility, geospatial data, text analysis.] -- * .font150[application in _science_] -- * .font150[better than similar packages] -- .font150[When in doubt, pre-submission enquiry! ] --- # Pre-submission enquiry? ```r magick_webshot_login("https://github.com/ropensci/onboarding/issues/110", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-19-1.png" width="1353" style="display: block; margin: auto;" /> --- # Pre-submission enquiry? ```r magick_webshot_login("https://github.com/ropensci/onboarding/issues/129", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-20-1.png" width="1353" style="display: block; margin: auto;" /> --- # The review process ```r webshot::webshot("https://github.com/ropensci/onboarding/issues/139", selector = "#show_issue") ``` <img src="slides_files/figure-html/unnamed-chunk-21-1.png" width="100" style="display: block; margin: auto;" /> --- # The review process: editor checks <img src="slides_files/figure-html/unnamed-chunk-22-1.png" width="350" style="display: block; margin: auto;" /> --- # The review process: reviews <img src="slides_files/figure-html/unnamed-chunk-25-1.png" width="100" style="display: block; margin: auto;" /> --- # The review process: reviews <img src="slides_files/figure-html/unnamed-chunk-26-1.png" width="100" style="display: block; margin: auto;" /> --- # The review process .font150[Ongoing discussion until acceptance and transfer] -- .font150[Often a blog post https://ropensci.org/tags/review/] --- # A data-driven overview? How to perform a *data analysis* of onboarding? -- .font150[Remember Jenny Bryan's talk last year?] -- .font150[Let's rectangle onboarding!] ```r # Meme image by Allie Brosh https://en.wikipedia.org/wiki/Hyperbole_and_a_Half magick::image_read("assets/rectangle.jpg") %>% magick::image_resize("300x300") ``` <img src="slides_files/figure-html/unnamed-chunk-27-1.png" width="400" style="display: block; margin: auto;" /> --- # Onboarding data in the issue tracker ```r magick_webshot("https://github.com/ropensci/onboarding/issues", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-28-1.png" width="1353" style="display: block; margin: auto;" /> --- # Weaving GitHub issue threads -- .font150[GitHub GraphQL API v4. Better than v3? Get only the data you need.] -- .font150[My experience] -- * .font150[Online API explorer] * .font150[`ghql` https://github.com/ropensci/ghql] * .font150[jq play to write a JSON wrangling magical code] * .font150[`jqr` https://github.com/ropensci/jqr] --- # GitHub API V4 explorer <img src="slides_files/figure-html/unnamed-chunk-29-1.png" width="1323" style="display: block; margin: auto;" /> --- # ghql and what? * .font150[Use the query defined previously via `ghql`] * .font150[Get raw JSON] * .font150[`writeClipboard`] --- # Learn how to transform JSON with jq PLAY! <img src="slides_files/figure-html/unnamed-chunk-30-1.png" width="1323" style="display: block; margin: auto;" /> --- # A minimal V4 example .font150[`get_contents` function of my `ghrecipes` package] <img src="slides_files/figure-html/unnamed-chunk-31-1.png" width="1307" style="display: block; margin: auto;" /> --- # A minimal V4 example: client creation ```r token <- Sys.getenv("GITHUB_GRAPHQL_TOKEN") cli <- ghql::GraphqlClient$new( url = "https://api.github.com/graphql", headers = httr::add_headers(Authorization = paste0("Bearer ", token)) ) cli$load_schema() ``` --- # A minimal V4 example: query writing ```r query <- paste0('query{ repository(owner: "', owner, '", name:"', repo,'"){ ref(qualifiedName: "master") { target { ... on Commit { id history(first: 1) { edges { node { tree{ entries { name } } } } } } } } } } ') ``` --- # A minimal V4 example: request\&wrangling ```r qry <- ghql::Query$new() qry$query('foobar', query) cli$exec(qry$queries$foobar) %>% jqr::jq("..|.entries?|select(.!=null)|.[].name") %>% as.character() %>% stringr::str_replace_all('\\\"', '') ``` --- # A minimal V4 example: in action ```r ghrecipes::get_contents(owner = "ropensci", repo = "onboarding") ``` ``` ## [1] "CNAME" "README.Rmd" ## [3] "README.md" "editor_template.md" ## [5] "editors_guide.md" "icon_lettering_color.png" ## [7] "issue_template.md" "news_template.md" ## [9] "packaging.png" "packaging_guide.md" ## [11] "policies.md" "review_request_template.md" ## [13] "reviewer_template.md" "reviewing_guide.md" ``` --- # Result: woven GitHub threads .font150[GitHub V4 magic + some wrangling later...] -- ```r threads <- readr::read_csv("data/clean_data.csv") threads ``` ``` ## # A tibble: 2,521 x 10 ## title created_at closed_at body user issue package ## <chr> <dttm> <dttm> <chr> <chr> <int> <chr> ## 1 rrli~ 2015-03-31 00:25:14 2015-04-13 23:26:38 "- 1~ rich~ 6 rrlite ## 2 rrli~ 2015-04-01 17:30:51 2015-04-13 23:26:38 "hey~ scko~ 6 rrlite ## 3 rrli~ 2015-04-01 17:36:03 2015-04-13 23:26:38 "@sc~ kart~ 6 rrlite ## 4 rrli~ 2015-04-02 03:36:09 2015-04-13 23:26:38 "Sur~ jero~ 6 rrlite ## 5 rrli~ 2015-04-02 03:50:43 2015-04-13 23:26:38 "IMO~ gabo~ 6 rrlite ## 6 rrli~ 2015-04-02 03:53:57 2015-04-13 23:26:38 "Ide~ rich~ 6 rrlite ## 7 rrli~ 2015-04-02 18:58:53 2015-04-13 23:26:38 "> H~ kart~ 6 rrlite ## 8 stpl~ 2015-04-08 23:56:17 2015-10-29 14:14:35 "- 1~ Robi~ 10 stplanr ## 9 rrli~ 2015-04-10 21:52:39 2015-04-13 23:26:38 "@ri~ stew~ 6 rrlite ## 10 rrli~ 2015-04-10 22:10:48 2015-04-13 23:26:38 "Tha~ rich~ 6 rrlite ## # ... with 2,511 more rows, and 3 more variables: is_review <lgl>, ## # commenter <chr>, role <chr> ``` --- # Result: woven GitHub threads ```r length(unique(threads$package)) ``` ``` ## [1] 70 ``` <img src="slides_files/figure-html/unnamed-chunk-35-1.png" style="display: block; margin: auto;" /> --- # Onboarding data in onboarded repos -- ```r magick_webshot_login("https://github.com/AustralianAntarcticDivision/bowerbird/commits/master", selector = ".public", expand = c(0, 800, 500, 10)) ``` <img src="slides_files/figure-html/unnamed-chunk-36-1.png" width="1336" style="display: block; margin: auto;" /> --- # Onboarding data in onboarded repos * .font150[Clone them all using `git2r` https://github.com/ropensci/git2r] -- * .font150[Reset them at pre-submission state using `git2r`. `git reset hard`... time-machine!] -- * .font150[Get commit logs using `gitsum`. https://github.com/lorenzwalthert/gitsum] -- * .font150[Get lines of code using `cloc`. https://github.com/hrbrmstr/cloc] -- * .font150[Get number of exported classes and functions using `devtools::parse_ns_file`] --- # Let the fun begin * .font150[Full code will be reported in blog posts.] * .font150[Visualization packages: `ggplot2`, `hrbrthemes`, `viridis`.] --- # How much work is onboarding? --- # Work done in repositories <img src="slides_files/figure-html/unnamed-chunk-37-1.png" width="896" style="display: block; margin: auto;" /> --- # Work done in repositories <img src="slides_files/figure-html/unnamed-chunk-38-1.png" width="1575" style="display: block; margin: auto;" /> --- # Work done in repositories <img src="slides_files/figure-html/unnamed-chunk-39-1.png" width="1575" style="display: block; margin: auto;" /> --- # Apparent age at submission -- <img src="slides_files/figure-html/unnamed-chunk-40-1.png" width="896" style="display: block; margin: auto;" /> --- # How big are packages? .font150[Work by authors Work for reviewers] --- # How big are packages? Lines of code CRAN data via Bob Rudis. <img src="slides_files/figure-html/unnamed-chunk-41-1.png" width="896" style="display: block; margin: auto;" /> --- # How big are packages? Exports CRAN data via Bob Rudis. <img src="slides_files/figure-html/unnamed-chunk-42-1.png" width="896" style="display: block; margin: auto;" /> --- # Reviewing time <img src="slides_files/figure-html/unnamed-chunk-43-1.png" width="896" style="display: block; margin: auto;" /> --- # Last notes on work quantification -- * .font150[Hard to define metrics] -- * .font150[Very hard working _volunteers_!] -- * .font150[Decreasing time by automation] -- * .font150[What about editors? In Tim Trice's words, _"guiding angels from start to finish during the entire onboarding and review process"_.] --- # A high-quality and... friendly process? -- ```r rtweet::tweet_shot("801761258097803264") %>% magick::image_crop("517x300+0+90") ``` <img src="slides_files/figure-html/unnamed-chunk-44-1.png" width="689" style="display: block; margin: auto;" /> --- # A high-quality and... friendly process? ```r rtweet::tweet_shot("967074247301566465") %>% magick::image_crop("517x300+0+90") ``` <img src="slides_files/figure-html/unnamed-chunk-45-1.png" width="689" style="display: block; margin: auto;" /> --- # Social weather of onboarding .font150[Ann Gentle's essay in http://open-advice.org/ Impressions, examples... more general approach for onboarding?] -- .font150[Tidy text analysis for the win! Reminder of Julia Silge's talk last year.] -- * .font150[Text cleaning involving tokenization in lines.] * .font150[`tidytext` and `sentimentr`] * .font150[https://www.tidytextmining.com/ by Julia Silge and David Robinson] --- # Most common words <img src="slides_files/figure-html/unnamed-chunk-46-1.png" width="896" style="display: block; margin: auto;" /> --- # Most common bigrams <img src="slides_files/figure-html/unnamed-chunk-47-1.png" width="896" style="display: block; margin: auto;" /> --- # Pairwise correlations <img src="slides_files/figure-html/unnamed-chunk-48-1.png" width="896" style="display: block; margin: auto;" /> --- # Sentiment -- <img src="slides_files/figure-html/unnamed-chunk-50-1.png" width="896" style="display: block; margin: auto;" /> --- # Words in negative lines <img src="slides_files/figure-html/unnamed-chunk-51-1.png" width="896" style="display: block; margin: auto;" /> --- # Negative sample ``` ## # A tibble: 15 x 2 ## line sentiment ## <chr> <dbl> ## 1 @ultinomics no more things, although do make sure to add mor~ -1.63 ## 2 not sure what you mean, but i'll use different object names ~ -1.20 ## 3 error in .local(.object, ...) : -1.00 ## 4 error: -1.00 ## 5 #### miscellaneous -1.00 ## 6 error: command failed (1) -0.866 ## 7 - get_plate_size_from_number_of_columns: maybe throwing an e~ -0.786 ## 8 "this code returns an error, which is good, but it would be ~ -0.744 ## 9 0 errors | 0 warnings | 0 notes -0.722 ## 10 once i get to use this package more, i'm sure i'll have more~ -0.721 ## 11 - i now realize i've pasted the spelling mistakes without th~ -0.707 ## 12 minor issues: -0.707 ## 13 ## minor issues -0.707 ## 14 replicates issue -0.707 ## 15 visualization issue -0.707 ``` --- # Most positive lines! ``` ## # A tibble: 15 x 2 ## line sentiment ## <chr> <dbl> ## 1 absolutely - it's really important to ensure it really has b~ 1.84 ## 2 overall, really easy to use and really nicely done. 1.73 ## 3 this package is a great and lightweight addition to working ~ 1.46 ## 4 i am very grateful for your approval and i very much look fo~ 1.26 ## 5 thank you very much for the constructive thoughts. 1.24 ## 6 thanks for the approval, all in all a very helpful and educa~ 1.22 ## 7 - really good use of helper functions 1.14 ## 8 - i believe the utf note is handled correctly and this is ju~ 1.13 ## 9 seem more unified and consistent. 1.13 ## 10 very much appreciated! 1.13 ## 11 - well organized, readable code 1.10 ## 12 - wow very extensive testing! well done, very thorough 1.10 ## 13 - i'm delighted that you find my work interesting and i'm ve~ 1.08 ## 14 thank you very much for your thorough and thoughtful review,~ 1.08 ## 15 great, thank you very much for accepting this package. i am ~ 1.07 ``` --- # Automate all the things .font150[Let humans focus on what humans are best at!] --- # Current automation .font150[ ```r R CMD check/BiocCheck #repository standards testthat::test_package() #functionality covr::package_coverage() #testing completeness devtools::spell_check() #documentation lintr::lint_package() #code style goodpractice::gp() #antipatterns/complexity ``` http://www.masalmon.eu/2017/06/17/automatictools/] --- # More automation -- * .font150[Submission from R? Like `devtools::release`] -- * .font150[Setting up the review project: https://github.com/ropenscilabs/pkgreviewr by Anna Krystalli] -- * .font150[Matching reviewers and packages via better volunteering data] -- * .font150[Running `goodpractice::gp` automatically and not locally] -- .font150[And even more ideas!] --- # Get involved! .font150[
rOpenSci
The official repo https://github.com/ropensci/onboarding
Read more https://ropensci.org/tags/review/
Volunteer to become a reviewer https://ropensci.org/onboarding/] --- # Thank you! .font150[Thank _you_ and thanks to...] -- ```r images_annotate <- function(images, texts, ...){ purrr::map2(images, texts, magick::image_annotate, ...) %>% magick::image_join() } set.seed(42) thank <- function(names){ load("adjectives.RData") compliments <- sample(adjectives, size = length(names)) glue::glue("https://github.com/{names}.png") %>% magick::image_read() %>% magick::image_resize("200x200") %>% as.list() %>% images_annotate(glue::glue("So {compliments}!"), boxcolor = "white", size = 15)%>% magick::image_join() %>% magick::image_append() } ``` --- # Thank you! satRday organizers ```r thank(c("DataWookie", "Axiematic", "jonmcalder", "theoniphotopoulou")) ``` <img src="slides_files/figure-html/unnamed-chunk-56-1.png" width="800" style="display: block; margin: auto;" /> ```r thank(c("kakaalikins", "katrintirok", "kviljoen", "satrdays")) ``` <img src="slides_files/figure-html/unnamed-chunk-56-2.png" width="800" style="display: block; margin: auto;" /> --- # Thank you! Feedback givers ```r thank(c("chucheria", "dacornu", "lauracion")) ``` <img src="slides_files/figure-html/unnamed-chunk-57-1.png" width="600" style="display: block; margin: auto;" /> --- # Thank you! Onboarding editors ```r thank(c("karthik", "noamross", "sckott")) ``` <img src="slides_files/figure-html/unnamed-chunk-58-1.png" width="600" style="display: block; margin: auto;" /> --- # Thank you! The faces of onboarding .font150[Minus editors. Only threads of onboarded packages.] <img src="slides_files/figure-html/unnamed-chunk-59-1.png" width="800" style="display: block; margin: auto;" /> http://www.masalmon.eu/satrday_keynote/slides ---