Skip to content

Add use_r_universe_badge() #1994

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

Merged
merged 18 commits into from
Jul 29, 2025
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
inst/doc
docs
internal

/.quarto/
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export(use_pkgdown_github_pages)
export(use_posit_cloud_badge)
export(use_proprietary_license)
export(use_r)
export(use_r_universe_badge)
export(use_rcpp)
export(use_rcpp_armadillo)
export(use_rcpp_eigen)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* `use_package(min_version = FALSE)` is treated the same as when `min_version`
is not specified (#2117, @salim-b).

* `use_r_universe_badge()` is a new function that creates a README badge indicating your package is available on [R-universe](https://r-universe.dev) and reporting the latest version (@olivroy, #1883).

* usethis's criteria for recognizing a project have expanded to include (#2133):
- a `.vscode/` directory, which Positron or VS Code might create
- a `_quarto.yml` file, typical of a Quarto project
Expand Down
37 changes: 36 additions & 1 deletion R/badge.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,23 @@
#' available on CRAN, powered by <https://www.r-pkg.org>
#' * `use_lifecycle_badge()`: badge declares the developmental stage of a
#' package according to <https://lifecycle.r-lib.org/articles/stages.html>.
#' * `use_r_universe_badge()`: `r lifecycle::badge("experimental")` badge
#' indicates what version of your package is available on [R-universe
Copy link
Member

@jennybc jennybc Jul 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm: it's "R-universe" (lowercase "u"), yeah? As opposed to "R-Universe" (uppercase "U").

#' ](https://r-universe.dev/search/). It is assumed that you have already
#' completed the
#' [necessary R-universe setup](https://docs.r-universe.dev/publish/set-up.html).
#' * `use_binder_badge()`: badge indicates that your repository can be launched
#' in an executable environment on <https://mybinder.org/>
#' * `use_posit_cloud_badge()`: badge indicates that your repository can be launched
#' in a [Posit Cloud](https://posit.cloud) project
#' * `use_rscloud_badge()`: `r lifecycle::badge("deprecated")`: Use
#' * `use_rscloud_badge()`: `r lifecycle::badge("deprecated")` Use
#' [use_posit_cloud_badge()] instead.
#'
#' @param badge_name Badge name. Used in error message and alt text
#' @param href,src Badge link and image src
#' @param stage Stage of the package lifecycle. One of "experimental",
#' "stable", "superseded", or "deprecated".
#' @eval param_repo_spec()
#' @seealso [use_github_action()] helps with the setup of various continuous
#' integration workflows, some of which will call these specialized badge
#' helpers.
Expand Down Expand Up @@ -144,6 +150,35 @@ use_binder_badge <- function(ref = git_default_branch(), urlpath = NULL) {

invisible(TRUE)
}
#' @rdname badges
#' @export
use_r_universe_badge <- function(repo_spec = NULL) {
check_is_package("use_r_universe_badge()")
pkg <- project_name()

if (is.null(repo_spec)) {
this_env <- current_call()
tryCatch(
github_url <- github_url(),
error = function(e) {
ui_abort(
c(
"x" = "Can't determine the R-universe owner of the {.pkg {pkg}} package.",
"!" = "No GitHub URL found in DESCRIPTION or the Git remotes.",
"i" = "Update the project configuration or provide an explicit {.arg repo_spec}."
),
call = this_env
)
}
)
repo_spec <- parse_repo_url(github_url)[["repo_spec"]]
}

owner <- parse_repo_spec(repo_spec)[["owner"]]
src <- glue("https://{owner}.r-universe.dev/{pkg}/badges/version")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't tell if the best form is what I currently have:

https://{owner}.r-universe.dev/{pkg}/badges/version

Or:

https://{owner}.r-universe.dev/badges/{pkg}

It feels like the prose and the example here sort of contradict each other?

https://docs.r-universe.dev/publish/set-up.html#badge-showing-the-number-of-the-deployed-version

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the markdown you get from the "copy markdown" button on a page like this:

https://r-lib.r-universe.dev/badges

looks like:

[![usethis status badge](https://r-lib.r-universe.dev/usethis/badges/version)](https://r-lib.r-universe.dev/usethis)

href <- glue("https://{owner}.r-universe.dev/{pkg}")
use_badge("R-universe version", href, src)
}

#' @rdname badges
#' @param url A link to an existing [Posit Cloud](https://posit.cloud)
Expand Down
1 change: 1 addition & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ knitr::opts_chunk$set(
[![CRAN status](https://www.r-pkg.org/badges/version/usethis)](https://CRAN.R-project.org/package=usethis)
[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)
[![Codecov test coverage](https://codecov.io/gh/r-lib/usethis/graph/badge.svg)](https://app.codecov.io/gh/r-lib/usethis)
[![R-universe version](https://r-lib.r-universe.dev/usethis/badges/version)](https://r-lib.r-universe.dev/usethis)
<!-- badges: end -->

usethis is a workflow package: it automates repetitive tasks that arise during project setup and development, both for R packages and non-package projects.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ status](https://www.r-pkg.org/badges/version/usethis)](https://CRAN.R-project.or
stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)
[![Codecov test
coverage](https://codecov.io/gh/r-lib/usethis/graph/badge.svg)](https://app.codecov.io/gh/r-lib/usethis)
[![R-universe
version](https://r-lib.r-universe.dev/usethis/badges/version)](https://r-lib.r-universe.dev/usethis)
<!-- badges: end -->

usethis is a workflow package: it automates repetitive tasks that arise
Expand Down
11 changes: 10 additions & 1 deletion man/badges.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 49 additions & 0 deletions tests/testthat/_snaps/badge.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,55 @@
! `stage` must be one of "experimental", "stable", "superseded", or "deprecated", not "eperimental".
i Did you mean "experimental"?

# use_r_universe_badge() needs to know the owner

Code
use_r_universe_badge()
Condition
Error in `use_r_universe_badge()`:
x Can't determine the R-universe owner of the {TESTPKG} package.
! No GitHub URL found in DESCRIPTION or the Git remotes.
i Update the project configuration or provide an explicit `repo_spec`.

---

Code
use_r_universe_badge("OWNER_DIRECT/SCRUBBED")
Message
! Can't find a README for the current project.
i See `usethis::use_readme_rmd()` for help creating this file.
i Badge link will only be printed to screen.
[ ] Copy and paste the following lines into 'README':
<!-- badges: start -->
[![R-universe version](https://OWNER_DIRECT.r-universe.dev/{TESTPKG}/badges/version)](https://OWNER_DIRECT.r-universe.dev/{TESTPKG})
<!-- badges: end -->

---

Code
use_r_universe_badge()
Message
! Can't find a README for the current project.
i See `usethis::use_readme_rmd()` for help creating this file.
i Badge link will only be printed to screen.
[ ] Copy and paste the following lines into 'README':
<!-- badges: start -->
[![R-universe version](https://OWNER_DESCRIPTION.r-universe.dev/{TESTPKG}/badges/version)](https://OWNER_DESCRIPTION.r-universe.dev/{TESTPKG})
<!-- badges: end -->

---

Code
use_r_universe_badge()
Message
! Can't find a README for the current project.
i See `usethis::use_readme_rmd()` for help creating this file.
i Badge link will only be printed to screen.
[ ] Copy and paste the following lines into 'README':
<!-- badges: start -->
[![R-universe version](https://OWNER_ORIGIN.r-universe.dev/{TESTPKG}/badges/version)](https://OWNER_ORIGIN.r-universe.dev/{TESTPKG})
<!-- badges: end -->

# use_posit_cloud_badge() handles bad and good input

Code
Expand Down
31 changes: 31 additions & 0 deletions tests/testthat/test-badge.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,37 @@ test_that("use_binder_badge() needs a github repository", {
)
})

test_that("use_r_universe_badge() needs to know the owner", {
skip_if_no_git_user()
local_interactive(FALSE)
withr::local_options(usethis.quiet = FALSE)
create_local_package()

expect_snapshot(
error = TRUE,
use_r_universe_badge(),
transform = scrub_testpkg
)

expect_snapshot(
use_r_universe_badge("OWNER_DIRECT/SCRUBBED"),
transform = scrub_testpkg
)

desc::desc_set_urls("https://github.com/OWNER_DESCRIPTION/SCRUBBED")
expect_snapshot(
use_r_universe_badge(),
transform = scrub_testpkg
)

use_git()
use_git_remote("origin", "https://github.com/OWNER_ORIGIN/SCRUBBED.git")
expect_snapshot(
use_r_universe_badge(),
transform = scrub_testpkg
)
})

test_that("use_posit_cloud_badge() handles bad and good input", {
create_local_project()
expect_snapshot(use_posit_cloud_badge(), error = TRUE)
Expand Down
Loading