Skip to content
Open
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
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_rcpp)
export(use_rcpp_armadillo)
export(use_rcpp_eigen)
export(use_readme_md)
export(use_readme_qmd)
export(use_readme_rmd)
export(use_release_issue)
export(use_reprex)
Expand Down
135 changes: 84 additions & 51 deletions R/readme.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
#' * R code to install from GitHub, if GitHub usage detected
#' * a basic example
#'
#' Use `Rmd` if you want a rich intermingling of code and output. Use `md` for a
#' basic README. `README.Rmd` will be automatically added to `.Rbuildignore`.
#' Use `qmd` or `Rmd` if you want a rich intermingling of code and output. Use `md` for a
#' basic README. `README.[R,q]md` will be automatically added to `.Rbuildignore`.
#' The resulting README is populated with default YAML frontmatter and R fenced
#' code blocks (`md`) or chunks (`Rmd`).
#' code blocks (`md`) or chunks (`Rmd`/`qmd`).
#'
#' If you use `Rmd`, you'll still need to render it regularly, to keep
#' If you use `[R,q]md`, you'll still need to render it regularly, to keep
#' `README.md` up-to-date. `devtools::build_readme()` is handy for this. You
#' could also use GitHub Actions to re-render `README.Rmd` every time you push.
#' could also use GitHub Actions to re-render `README.[R,q]md` every time you push.
#' An example workflow can be found in the `examples/` directory here:
#' <https://github.com/r-lib/actions/>.
#'
#' If the current project is a Git repo, then `use_readme_rmd()` automatically
#' configures a pre-commit hook that helps keep `README.Rmd` and `README.md`,
#' If the current project is a Git repo, then `use_readme_[r,q]md()` automatically
#' configures a pre-commit hook that helps keep `README.[R,q]md` and `README.md`,
#' synchronized. The hook creates friction if you try to commit when
#' `README.Rmd` has been edited more recently than `README.md`. If this hook
#' `README.[R,q]md` has been edited more recently than `README.md`. If this hook
#' causes more problems than it solves for you, it is implemented in
#' `.git/hooks/pre-commit`, which you can modify or even delete.
#'
Expand All @@ -32,75 +32,108 @@
#' @examples
#' \dontrun{
#' use_readme_rmd()
#' use_readme_qmd()
#' use_readme_md()
#' }
use_readme_rmd <- function(open = rlang::is_interactive()) {
use_readme("Rmd", open = open)
}

#' @export
#' @rdname use_readme_rmd
use_readme_qmd <- function(open = rlang::is_interactive()) {
use_readme("qmd", open = open)
}

#' @export
#' @rdname use_readme_rmd
use_readme_md <- function(open = rlang::is_interactive()) {
use_readme("md", open = open)
}

#' Helper to create README files
#'
#' @description
#' This function switches between the three file formats supported for READMEs,
#' and neatly handles file creation for all of them.
#'
#' @noRd
use_readme <- function(
fmt = c("Rmd", "md", "qmd"),
open = rlang::is_interactive()
) {
check_is_project()
check_installed("rmarkdown")
fmt <- rlang::arg_match(fmt)

# Check dependencies and conflicts.
if (fmt == "Rmd") {
check_installed("rmarkdown")
if (fs::file_exists(proj_path("README.qmd"))) {
cli::cli_abort(
"Can't have both {.file README.Rmd} and {.file README.qmd}. Delete {.file README.qmd} if you want to generate {.file README.Rmd}."
)
}
} else if (fmt == "qmd") {
check_installed("quarto")
if (fs::file_exists(proj_path("README.Rmd"))) {
cli::cli_abort(
"Can't have both {.file README.Rmd} and {.file README.qmd}. Delete {.file README.Rmd} if you want to generate {.file README.qmd}."
)
}
}

# Get some info about the package/project function was called from
is_pkg <- is_package()
repo_spec <- tryCatch(target_repo_spec(ask = FALSE), error = function(e) NULL)
nm <- if (is_pkg) "Package" else "Project"

# build out arguments for creating template
args <- switch(
fmt,
Rmd = list(Rmd = TRUE, filename = "README.Rmd", needs_render = TRUE),
md = list(needs_render = FALSE),
qmd = list(quarto = TRUE, filename = "README.qmd", needs_render = TRUE)
)
data <- list2(
!!nm := project_name(),
Rmd = TRUE,
on_github = !is.null(repo_spec),
github_spec = repo_spec
github_spec = repo_spec,
!!!args
)

# Create the template, interpolating values from `data` as specified
new <- use_template(
if (is_pkg) "package-README" else "project-README",
"README.Rmd",
glue::glue("README.", fmt),
data = data,
ignore = is_pkg,
ignore = if (fmt %in% c("Rmd", "qmd")) is_pkg else FALSE,
open = open
)
if (!new) {
return(invisible(FALSE))
}

# Make some checks
if (is_pkg && !data$on_github) {
ui_bullets(c(
"_" = "Update {.path {pth('README.Rmd')}} to include installation instructions."
))
msg <- switch(
fmt,
rmd = "Update {.path {pth('README.Rmd')}} to include installation instructions.",
md = "Update {.path {pth('README.md')}} to include installation instructions.",
qmd = "Update {.path {pth('README.qmd')}} to include installation instructions."
)
ui_bullets(c("_" = msg))
}

if (uses_git()) {
# More checks, specific to renderable README
if (fmt %in% c("Rmd", "qmd") && uses_git()) {
if (!new) {
return(invisible(FALSE))
}

use_git_hook(
"pre-commit",
render_template("readme-rmd-pre-commit.sh")
)
}

invisible(TRUE)
}

#' @export
#' @rdname use_readme_rmd
use_readme_md <- function(open = rlang::is_interactive()) {
check_is_project()
is_pkg <- is_package()
repo_spec <- tryCatch(target_repo_spec(ask = FALSE), error = function(e) NULL)
nm <- if (is_pkg) "Package" else "Project"
data <- list2(
!!nm := project_name(),
Rmd = FALSE,
on_github = !is.null(repo_spec),
github_spec = repo_spec
)

new <- use_template(
if (is_pkg) "package-README" else "project-README",
"README.md",
data = data,
open = open
)

if (is_pkg && !data$on_github) {
ui_bullets(c(
"_" = "Update {.path {pth('README.md')}} to include installation instructions."
))
invisible(TRUE)
} else {
invisible(new)
}

invisible(new)
}
32 changes: 24 additions & 8 deletions inst/templates/package-README
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,23 @@ knitr::opts_chunk$set(
```
{{/Rmd}}

{{#quarto}}
---
title: {{{ Package }}}
knitr:
opts_chunk:
collapse: true
comment: '#>'
fig.path: "man/figures/README-"
out.width: "100%"
format: gfm
---

<!-- README.md is generated from README.qmd. Please edit that file -->
{{/quarto}}
{{^quarto}}
# {{{ Package }}}
{{/quarto}}

<!-- badges: start -->
<!-- badges: end -->
Expand Down Expand Up @@ -44,23 +60,23 @@ You can install the development version of {{{ Package }}} like so:

This is a basic example which shows you how to solve a common problem:

{{#Rmd}}
{{#needs_render}}
```{r example}
{{/Rmd}}
{{^Rmd}}``` r
{{/Rmd}}
{{/needs_render}}
{{^needs_render}}``` r
{{/needs_render}}
library({{Package}})
## basic example code
```

{{#Rmd}}
What is special about using `README.Rmd` instead of just `README.md`? You can include R chunks like so:
{{#needs_render}}
What is special about using `{{{ filename }}}` instead of just `README.md`? You can include R chunks like so:

```{r cars}
summary(cars)
```

You'll still need to render `README.Rmd` regularly, to keep `README.md` up-to-date. `devtools::build_readme()` is handy for this.
You'll still need to render `{{{ filename }}}` regularly, to keep `README.md` up-to-date. `devtools::build_readme()` is handy for this.

You can also embed plots, for example:

Expand All @@ -69,4 +85,4 @@ plot(pressure)
```

In that case, don't forget to commit and push the resulting figure files, so they display on GitHub and CRAN.
{{/Rmd}}
{{/needs_render}}
24 changes: 19 additions & 5 deletions inst/templates/project-README
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,36 @@ knitr::opts_chunk$set(
)
```
{{/Rmd}}
{{#quarto}}
---
title: {{{ Project }}}
knitr:
opts_chunk:
collapse: true
comment: '#>'
fig.path: "man/figures/README-"
out.width: "100%"
format: gfm
---

<!-- README.md is generated from README.qmd. Please edit that file -->
{{/quarto}}
{{^quarto}}
# {{{ Project }}}

{{/quarto}}
<!-- badges: start -->
<!-- badges: end -->

The goal of {{{ Project }}} is to ...

{{#Rmd}}
What is special about using `README.Rmd` instead of just `README.md`? You can include R chunks like so:
{{#needs_render}}
What is special about using `{{{ filename }}}` instead of just `README.md`? You can include R chunks like so:

```{r cars}
summary(cars)
```

You'll still need to render `README.Rmd` regularly, to keep `README.md` up-to-date.
You'll still need to render `{{{ filename }}}` regularly, to keep `README.md` up-to-date.

You can also embed plots, for example:

Expand All @@ -36,4 +50,4 @@ plot(pressure)
```

In that case, don't forget to commit and push the resulting figure files, so they display on GitHub.
{{/Rmd}}
{{/needs_render}}
6 changes: 3 additions & 3 deletions inst/templates/readme-rmd-pre-commit.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/bin/bash
README=($(git diff --cached --name-only | grep -Ei '^README\.[R]?md$'))
README=($(git diff --cached --name-only | grep -Ei '^README\.([R,q]?md)$'))
MSG="use 'git commit --no-verify' to override this check"

if [[ ${#README[@]} == 0 ]]; then
exit 0
fi

if [[ README.Rmd -nt README.md ]]; then
echo -e "README.md is out of date; please re-knit README.Rmd\n$MSG"
if [[ README.Rmd -nt README.md || README.qmd -nt README.md ]]; then
echo -e "README.md is out of date; please re-knit README.Rmd or README.qmd\n$MSG"
exit 1
elif [[ ${#README[@]} -lt 2 ]]; then
echo -e "README.Rmd and README.md should be both staged\n$MSG"
Expand Down
20 changes: 12 additions & 8 deletions man/use_readme_rmd.Rd

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

Loading
Loading