├── inst └── WORDLIST ├── LICENSE ├── .Rbuildignore ├── .gitignore ├── R ├── ghstars_global.R ├── ghstars-package.R ├── get_pkg_repo.R ├── plot_stars.R └── get_stars.R ├── man ├── figures │ ├── ggplot2_star_history.PNG │ ├── README-unnamed-chunk-1-1.png │ └── README-unnamed-chunk-2-1.png ├── ghstars-package.Rd ├── get_repo_metrics.Rd └── get_repo_star_history.Rd ├── ghstars.Rproj ├── NAMESPACE ├── DESCRIPTION ├── README.Rmd └── README.md /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Repo 2 | Repos 3 | repo 4 | repos 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2020 2 | COPYRIGHT HOLDER: Thomas Neitmann 3 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README.Rmd$ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /R/ghstars_global.R: -------------------------------------------------------------------------------- 1 | ghstars_global <- new.env(parent = emptyenv()) 2 | 3 | ghstars_global$pkg_db <- NULL 4 | -------------------------------------------------------------------------------- /man/figures/ggplot2_star_history.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomas-neitmann/ghstars/HEAD/man/figures/ggplot2_star_history.PNG -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomas-neitmann/ghstars/HEAD/man/figures/README-unnamed-chunk-1-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomas-neitmann/ghstars/HEAD/man/figures/README-unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /R/ghstars-package.R: -------------------------------------------------------------------------------- 1 | #' @importFrom ggplot2 autoplot ggplot aes_string geom_line geom_step theme 2 | #' scale_color_brewer labs 3 | #' @keywords internal 4 | "_PACKAGE" 5 | 6 | # The following block is used by usethis to automatically manage 7 | # roxygen namespace tags. Modify with care! 8 | ## usethis namespace: start 9 | ## usethis namespace: end 10 | NULL 11 | -------------------------------------------------------------------------------- /ghstars.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | StripTrailingWhitespace: Yes 16 | 17 | BuildType: Package 18 | PackageUseDevtools: Yes 19 | PackageInstallArgs: --no-multiarch --with-keep.source 20 | -------------------------------------------------------------------------------- /man/ghstars-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ghstars-package.R 3 | \docType{package} 4 | \name{ghstars-package} 5 | \alias{ghstars} 6 | \alias{ghstars-package} 7 | \title{ghstars: Retrieve GitHub Stars for any Repository} 8 | \description{ 9 | Provides utility functions to retrieve and plot the GitHub star 10 | history of any repository. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(plot,ghmetrics_tbl) 4 | S3method(plot,ghstars_history_tbl) 5 | export(get_pkg_metrics) 6 | export(get_pkg_star_history) 7 | export(get_repo_metrics) 8 | export(get_repo_star_history) 9 | importFrom(ggplot2,aes_string) 10 | importFrom(ggplot2,autoplot) 11 | importFrom(ggplot2,geom_line) 12 | importFrom(ggplot2,geom_step) 13 | importFrom(ggplot2,ggplot) 14 | importFrom(ggplot2,labs) 15 | importFrom(ggplot2,scale_color_brewer) 16 | importFrom(ggplot2,theme) 17 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ghstars 2 | Type: Package 3 | Title: Retrieve GitHub Stars for any Repository 4 | Version: 0.1.0 5 | Author: Thomas Neitmann 6 | Maintainer: Thomas Neitmann 7 | Description: Provides utility functions to retrieve and plot the star 8 | history of any GitHub repository. 9 | Imports: ggcharts, 10 | ggplot2, 11 | gh, 12 | memoise, 13 | rlang 14 | License: MIT + file LICENSE 15 | Encoding: UTF-8 16 | LazyData: true 17 | RoxygenNote: 7.1.0 18 | Roxygen: list(markdown = TRUE) 19 | -------------------------------------------------------------------------------- /R/get_pkg_repo.R: -------------------------------------------------------------------------------- 1 | get_pkg_repo <- function(pkg) { 2 | repo <- vapply(pkg, get_pkg_repo_single, "") 3 | pkg_without_repo <- pkg[is.na(repo)] 4 | 5 | if (length(pkg_without_repo)) { 6 | msg <- paste0( 7 | "Could not find a GitHub repo for package ", 8 | paste(pkg_without_repo, collapse = ", "), "." 9 | ) 10 | if (length(pkg_without_repo) == length(pkg)) { 11 | rlang::abort(msg) 12 | } 13 | rlang::warn(msg) 14 | } 15 | 16 | repo 17 | } 18 | 19 | get_pkg_repo_single <- memoise::memoise(function(pkg) { 20 | stopifnot(length(pkg) == 1L) 21 | if (is.null(ghstars_global$pkg_db)) { 22 | ghstars_global$pkg_db <- tools::CRAN_package_db() 23 | } 24 | pkg_db <- ghstars_global$pkg_db 25 | url <- pkg_db$URL[pkg_db$Package == pkg] 26 | if (length(url) == 0L) { 27 | return(structure(NA_character_, names = pkg)) 28 | } 29 | 30 | url <- unlist(strsplit(url, ", ")) 31 | gh_url <- url[grepl("github", url)] 32 | if (length(gh_url) == 0L) { 33 | return(structure(NA_character_, names = pkg)) 34 | } 35 | 36 | match <- gregexpr("github.com/", gh_url)[[1L]] 37 | repo <- substr(gh_url, match + attr(match, "match.length"), nchar(gh_url)) 38 | # Remove trailing slash if present 39 | if (substr(repo, nchar(repo), nchar(repo)) == "/") { 40 | repo <- substr(repo, 1L, nchar(repo)-1L) 41 | } 42 | names(repo) <- pkg 43 | repo 44 | }) 45 | -------------------------------------------------------------------------------- /man/get_repo_metrics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_stars.R 3 | \name{get_repo_metrics} 4 | \alias{get_repo_metrics} 5 | \alias{get_pkg_metrics} 6 | \title{Retrieve Metrics of a GitHub Repo} 7 | \usage{ 8 | get_repo_metrics(repo) 9 | 10 | get_pkg_metrics(pkg) 11 | } 12 | \arguments{ 13 | \item{repo}{\code{character}. Repository name(s) in the form \code{user/reponame}} 14 | 15 | \item{pkg}{\code{character}. Name of an \code{R} package.} 16 | } 17 | \value{ 18 | An object of class \code{c("ghmetrics_tbl", "data.frame")} with 2 columns: 19 | \itemize{ 20 | \item \code{repo} Name of the repository 21 | \item \code{stars} Number of stars 22 | \item \code{forks} Number of forks 23 | \item \code{watcher} Number of watchers 24 | \item \code{open_issues} Number of open issue 25 | } 26 | } 27 | \description{ 28 | Retrieve the current number of stars, forks, watchers and open issues of a 29 | GitHub repository 30 | } 31 | \details{ 32 | \code{get_pkg_metrics()} is a shortcut for retrieving the metrics of an \code{R} package. 33 | The function tries to find the GitHub repository of the package. If it 34 | succeeds it continues calling \code{get_repo_metrics()}. If it fails either a warning 35 | or an error is thrown depending on whether a GitHub repo couldn't be 36 | found for some or all \code{pkg}, respectively. 37 | } 38 | \examples{ 39 | \dontrun{ 40 | get_repo_metrics("thomas-neitmann/mdthemes") 41 | 42 | get_pkg_metrics(c("Rcpp", "scales")) 43 | } 44 | 45 | } 46 | \author{ 47 | Thomas Neitmann 48 | } 49 | -------------------------------------------------------------------------------- /man/get_repo_star_history.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_stars.R 3 | \name{get_repo_star_history} 4 | \alias{get_repo_star_history} 5 | \alias{get_pkg_star_history} 6 | \title{Retrieve GitHub Repo Star Hisotry} 7 | \usage{ 8 | get_repo_star_history(repo) 9 | 10 | get_pkg_star_history(pkg) 11 | } 12 | \arguments{ 13 | \item{repo}{\code{character}. Repository name(s) in the form \code{user/reponame}} 14 | 15 | \item{pkg}{\code{character}. Name of an \code{R} package.} 16 | } 17 | \value{ 18 | An object of class \code{c("ghstars_history_tbl", "data.frame")} with 5 columns: 19 | \itemize{ 20 | \item \code{repo}: Name of the repository 21 | \item \code{date}: Date repository was starred 22 | \item \code{day}: Number of days since first star 23 | \item \code{stars}: Number of stars given at the current \code{date} 24 | \item \code{cumulative_stars}: Cumulative number of stars up to current \code{date} 25 | } 26 | } 27 | \description{ 28 | Retrieve the star history of any GitHub repository 29 | } 30 | \details{ 31 | \code{get_pkg_star_history()} is a shortcut for retrieving the star history of an 32 | \code{R} package. The function tries to find the GitHub repository of the package. 33 | If it succeeds it continues calling \code{get_repo_star_history()}. If it fails either 34 | a warning or an error is thrown depending on whether a GitHub repo couldn't be 35 | found for some or all \code{pkg}, respectively. 36 | } 37 | \examples{ 38 | \dontrun{ 39 | get_repo_star_history("thomas-neitmann/mdthemes") 40 | } 41 | 42 | } 43 | \author{ 44 | Thomas Neitmann 45 | } 46 | -------------------------------------------------------------------------------- /R/plot_stars.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | plot.ghstars_history_tbl <- function(x, ..., geom = "step") { 3 | geom <- match.arg(geom, c("step", "line")) 4 | n_repos <- length(unique(x$repo)) 5 | if (n_repos == 1L) { 6 | plot_single_repo(x, geom) 7 | } else { 8 | plot_multiple_repos(x, geom) 9 | } 10 | } 11 | 12 | plot_single_repo <- function(ghstars_tbl, geom = "step") { 13 | repo <- ghstars_tbl$repo[1L] 14 | geom <- paste0("geom_", geom) 15 | ggplot(ghstars_tbl, aes_string("date", "cumulative_stars")) + 16 | eval(call(geom, size = 1, color = "darkorange")) + 17 | ggcharts::theme_ng(grid = "xy", ticks = "x") + 18 | theme(legend.position = c(.05, .95)) + 19 | labs( 20 | x = NULL, 21 | y = NULL, 22 | title = paste("GitHub Star History of", repo) 23 | ) 24 | } 25 | 26 | plot_multiple_repos <- function(ghstars_tbl, geom = "step") { 27 | geom <- paste0("geom_", geom) 28 | ggplot(ghstars_tbl, aes_string("day", "cumulative_stars", color = "repo", group = "repo")) + 29 | eval(call(geom, size = 1)) + 30 | scale_color_brewer(palette = "Set2", name = NULL) + 31 | ggcharts::theme_ng(grid = "XY") + 32 | theme( 33 | legend.position = c(.03, 1), 34 | legend.justification = c("left", "top") 35 | ) + 36 | labs( 37 | x = "Days Since 1st Star", 38 | y = NULL, 39 | title = "GitHub Star History" 40 | ) 41 | } 42 | 43 | #' @export 44 | plot.ghmetrics_tbl <- function(x, ..., metric = c("stars", "forks", "watchers", "open_issues")) { 45 | metric <- match.arg(metric) 46 | args <- list( 47 | data = x, 48 | x = quote(repo), 49 | y = as.symbol(metric) 50 | ) 51 | 52 | old_theme <- ggcharts::ggcharts_set_theme("theme_ng") 53 | on.exit(ggcharts::ggcharts_set_theme(old_theme)) 54 | do.call(ggcharts::bar_chart, args) + 55 | labs(x = NULL, y = tools::toTitleCase(gsub("_", " ", metric))) 56 | } 57 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "ghstars" 3 | output: github_document 4 | --- 5 | 6 | ```{r setup, include=FALSE} 7 | knitr::opts_chunk$set( 8 | fig.path = "man/figures/README-", 9 | fig.align = "left", 10 | out.width = "70%", 11 | message = FALSE, 12 | error = FALSE 13 | ) 14 | ``` 15 | 16 | ## Motivation 17 | 18 | Developers love GitHub. Even more so, they love seeing the stars of their repos rise. This is evident in the popularity of website's such [star-history.t9t.io](https://star-history.t9t.io/) which created plots like this one. 19 | 20 | 21 | 22 | Having a website to create these kind of plots in great but I thought it would be even better to have an `R` package to do so. That's why I created `{ghstars}`. 23 | 24 | ## Overview 25 | 26 | `get_repo_star_history()` is the work horse of `{ghstars}`. It fetches the star history of any GitHub repository via the GitHub API thanks to the `{gh}` package. Its associated plot method creates a stunning visualization of the star history. 27 | 28 | ```{r} 29 | library(ghstars) 30 | star_history <- get_repo_star_history("thomas-neitmann/ggcharts") 31 | head(star_history) 32 | plot(star_history) 33 | ``` 34 | 35 | `get_pkg_star_history()` is a shortcut for retrieving the star history of `R` packages. It allows you to pass just the package name instead of the whole repo name as its argument. The function searches for the GitHub repo of the package. If it is successful it calls `get_repo_star_history()`. If not, an error is thrown. 36 | 37 | ```{r} 38 | star_histories <- get_pkg_star_history(c("Rcpp", "scales")) 39 | plot(star_histories) 40 | ``` 41 | 42 | 43 | ## Installation 44 | 45 | The package is currently only available from GitHub. 46 | 47 | ```r 48 | if (!"remotes" %in% installed.packages()) { 49 | install.packages("remotes") 50 | } 51 | remotes::install_github("thomas-neitmann/ghstars", upgrade = "never") 52 | ``` 53 | 54 | If you get an error when trying to install, run this code and then try to install once again. 55 | 56 | ```r 57 | Sys.setenv(R_REMOTES_NO_ERRORS_FROM_WARNINGS = "true") 58 | ``` 59 | 60 | If the installation still fails please open an issue. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ghstars 2 | ================ 3 | 4 | ## Motivation 5 | 6 | Developers love GitHub. Even more so, they love seeing the stars of 7 | their repos rise. This is evident in the popularity of website’s such 8 | [star-history.t9t.io](https://star-history.t9t.io/) which created plots 9 | like this one. 10 | 11 | 12 | 13 | Having a website to create these kind of plots in great but I thought it 14 | would be even better to have an `R` package to do so. That’s why I 15 | created `{ghstars}`. 16 | 17 | ## Overview 18 | 19 | `get_repo_star_history()` is the work horse of `{ghstars}`. It fetches 20 | the star history of any GitHub repository via the GitHub API thanks to 21 | the `{gh}` package. Its associated plot method creates a stunning 22 | visualization of the star history. 23 | 24 | ``` r 25 | library(ghstars) 26 | star_history <- get_repo_star_history("thomas-neitmann/ggcharts") 27 | head(star_history) 28 | ``` 29 | 30 | ## repo date day stars cumulative_stars 31 | ## 1 thomas-neitmann/ggcharts 2020-01-07 0 1 1 32 | ## 2 thomas-neitmann/ggcharts 2020-01-14 7 1 2 33 | ## 3 thomas-neitmann/ggcharts 2020-01-28 21 1 3 34 | ## 4 thomas-neitmann/ggcharts 2020-02-01 25 1 4 35 | ## 5 thomas-neitmann/ggcharts 2020-02-02 26 1 5 36 | ## 6 thomas-neitmann/ggcharts 2020-02-03 27 2 7 37 | 38 | ``` r 39 | plot(star_history) 40 | ``` 41 | 42 | 43 | 44 | `get_pkg_star_history()` is a shortcut for retrieving the star history 45 | of `R` packages. It allows you to pass just the package name instead of 46 | the whole repo name as its argument. The function searches for the 47 | GitHub repo of the package. If it is successful it calls 48 | `get_repo_star_history()`. If not, an error is thrown. 49 | 50 | ``` r 51 | star_histories <- get_pkg_star_history(c("Rcpp", "scales")) 52 | plot(star_histories) 53 | ``` 54 | 55 | 56 | 57 | ## Installation 58 | 59 | The package is currently only available from GitHub. 60 | 61 | ``` r 62 | if (!"remotes" %in% installed.packages()) { 63 | install.packages("remotes") 64 | } 65 | remotes::install_github("thomas-neitmann/ghstars", upgrade = "never") 66 | ``` 67 | 68 | If you get an error when trying to install, run this code and then try 69 | to install once again. 70 | 71 | ``` r 72 | Sys.setenv(R_REMOTES_NO_ERRORS_FROM_WARNINGS = "true") 73 | ``` 74 | 75 | If the installation still fails please open an issue. 76 | -------------------------------------------------------------------------------- /R/get_stars.R: -------------------------------------------------------------------------------- 1 | #' Retrieve GitHub Repo Star Hisotry 2 | #' 3 | #' Retrieve the star history of any GitHub repository 4 | #' 5 | #' @param repo `character`. Repository name(s) in the form `user/reponame` 6 | #' @param pkg `character`. Name of an `R` package. 7 | #' 8 | #' @details 9 | #' `get_pkg_star_history()` is a shortcut for retrieving the star history of an 10 | #' `R` package. The function tries to find the GitHub repository of the package. 11 | #' If it succeeds it continues calling `get_repo_star_history()`. If it fails either 12 | #' a warning or an error is thrown depending on whether a GitHub repo couldn't be 13 | #' found for some or all `pkg`, respectively. 14 | #' 15 | #' @return 16 | #' An object of class `c("ghstars_history_tbl", "data.frame")` with 5 columns: 17 | #' * `repo`: Name of the repository 18 | #' * `date`: Date repository was starred 19 | #' * `day`: Number of days since first star 20 | #' * `stars`: Number of stars given at the current `date` 21 | #' * `cumulative_stars`: Cumulative number of stars up to current `date` 22 | #' 23 | #' @author Thomas Neitmann 24 | #' 25 | #' @examples 26 | #' \dontrun{ 27 | #' get_repo_star_history("thomas-neitmann/mdthemes") 28 | #' } 29 | #' 30 | #' @export 31 | get_repo_star_history <- function(repo) { 32 | if (length(repo) == 1L) { 33 | return(get_repo_star_history_single(repo)) 34 | } 35 | ghstars_list <- lapply(repo, get_repo_star_history_single) 36 | do.call(rbind, ghstars_list) 37 | } 38 | 39 | #' @rdname get_repo_star_history 40 | #' @export 41 | get_pkg_star_history <- function(pkg) { 42 | repo <- get_pkg_repo(pkg) 43 | get_repo_star_history(repo) 44 | } 45 | 46 | get_repo_star_history_single <- memoise::memoise(function(repo) { 47 | stars <- gh::gh( 48 | endpoint = paste0("GET /repos/", repo, "/stargazers"), 49 | .accept = "application/vnd.github.v3.star+json", 50 | .limit = Inf 51 | ) 52 | starred_at <- vapply(stars, `[[`, "", "starred_at") 53 | date_time <- strsplit(starred_at, "T") 54 | date_chr <- vapply(date_time, `[`, "", 1L) 55 | stars <- table(date_chr) 56 | date <- as.Date(names(stars)) 57 | structure( 58 | data.frame( 59 | repo = repo, 60 | date = date, 61 | day = as.integer(date - date[1L]), 62 | stars = c(stars), 63 | cumulative_stars = cumsum(stars), 64 | row.names = NULL, 65 | stringsAsFactors = FALSE 66 | ), 67 | class = c("ghstars_history_tbl", "data.frame") 68 | ) 69 | }) 70 | 71 | #' Retrieve Metrics of a GitHub Repo 72 | #' 73 | #' Retrieve the current number of stars, forks, watchers and open issues of a 74 | #' GitHub repository 75 | #' 76 | #' @param repo `character`. Repository name(s) in the form `user/reponame` 77 | #' @param pkg `character`. Name of an `R` package. 78 | #' 79 | #' @details 80 | #' `get_pkg_metrics()` is a shortcut for retrieving the metrics of an `R` package. 81 | #' The function tries to find the GitHub repository of the package. If it 82 | #' succeeds it continues calling `get_repo_metrics()`. If it fails either a warning 83 | #' or an error is thrown depending on whether a GitHub repo couldn't be 84 | #' found for some or all `pkg`, respectively. 85 | #' 86 | #' @return 87 | #' An object of class `c("ghmetrics_tbl", "data.frame")` with 2 columns: 88 | #' * `repo` Name of the repository 89 | #' * `stars` Number of stars 90 | #' * `forks` Number of forks 91 | #' * `watcher` Number of watchers 92 | #' * `open_issues` Number of open issue 93 | #' 94 | #' @author Thomas Neitmann 95 | #' 96 | #' @examples 97 | #' \dontrun{ 98 | #' get_repo_metrics("thomas-neitmann/mdthemes") 99 | #' 100 | #' get_pkg_metrics(c("Rcpp", "scales")) 101 | #' } 102 | #' 103 | #' @export 104 | get_repo_metrics <- function(repo) { 105 | metrics <- lapply(repo, get_repo_metrics_single) 106 | do.call(rbind, metrics) 107 | } 108 | 109 | #' @rdname get_repo_metrics 110 | #' @export 111 | get_pkg_metrics <- function(pkg) { 112 | repo <- get_pkg_repo(pkg) 113 | get_repo_metrics(repo) 114 | } 115 | 116 | get_repo_metrics_single <- memoise::memoise(function(repo) { 117 | which <- c( 118 | stars = "stargazers_count", 119 | forks = "forks_count", 120 | watchers = "subscribers_count", 121 | open_issues = "open_issues_count" 122 | ) 123 | 124 | repo_info <- gh::gh(endpoint = paste0("GET /repos/", repo)) 125 | metrics <- data.frame(repo, repo_info[which], stringsAsFactors = FALSE) 126 | colnames(metrics) <- c("repo", names(which)) 127 | class(metrics) <- c("ghmetrics_tbl", "data.frame") 128 | 129 | metrics 130 | }) 131 | --------------------------------------------------------------------------------