Skip to content

Commit

Permalink
feat: New plan_release(), replaces init_release() and `pre_releas…
Browse files Browse the repository at this point in the history
…e()` (#803)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: krlmlr <[email protected]>
  • Loading branch information
3 people authored Nov 17, 2024
1 parent 317f8f1 commit 9c6d74c
Show file tree
Hide file tree
Showing 33 changed files with 509 additions and 391 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
cache-version: rcc-smoke-2
needs: check, website
# Beware of using dev pkgdown here, has brought in dev dependencies in the past
extra-packages: any::rcmdcheck r-lib/roxygen2 any::decor r-lib/styler r-lib/pkgdown deps::.
extra-packages: any::rcmdcheck r-lib/roxygen2 any::decor r-lib/styler#1235 r-lib/pkgdown deps::.

- name: Install package
run: |
Expand Down
3 changes: 3 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ Suggests:
gert (>= 1.4.0),
gh,
httptest2,
job,
jsonlite,
knitr,
pkgbuild,
pkgload,
rhub,
rmarkdown,
rstudioapi,
testthat (>= 3.1.10),
urlchecker,
vctrs,
whisker,
withr
Expand Down
3 changes: 1 addition & 2 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ export(create_demo_project)
export(finalize_version)
export(get_last_tag)
export(get_top_level_commits)
export(init_release)
export(local_demo_project)
export(plan_release)
export(post_release)
export(pre_release)
export(release)
export(tag_version)
export(unbump_version)
Expand Down
9 changes: 5 additions & 4 deletions R/api-bump-version.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
#'
#' @example man/examples/bump-version.R
bump_version <- function(
which = c("dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major"),
...,
no_change_behavior = c("bump", "noop", "fail"),
check_default_branch = TRUE) {
which = c("dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major"),
...,
no_change_behavior = c("bump", "noop", "fail"),
check_default_branch = TRUE
) {
check_dots_empty()

which <- arg_match(which)
Expand Down
5 changes: 3 additions & 2 deletions R/api-update-news.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
#' @return None
#' @export
update_news <- function(
messages = NULL,
which = c("auto", "samedev", "dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major")) {
messages = NULL,
which = c("auto", "samedev", "dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major")
) {
which <- arg_match(which)

local_repo()
Expand Down
209 changes: 134 additions & 75 deletions R/auto.R
Original file line number Diff line number Diff line change
@@ -1,89 +1,73 @@
#' Automating CRAN release
#'
#' `init_release()` and `pre_release()` are run
#' `plan_release()` is run
#' when a milestone in the development of a package is reached
#' and it is ready to be sent to CRAN.
#' By default, this function will initiate a pre-release, indicated by `9900`
#' in the fourth component of the version number.
#' Pass `which = "patch"`, `which = "minor"`, or `which = "major"` to
#' initiate a release with the corresponding version number.
#'
#' `init_release()`:
#' - Ensures that no modified files are in the git index.
#' - Creates a release branch and bumps version to a non-development version which should be sent to CRAN.
#' `plan_release()`:
#' - Ensures that no modified files are in the Git index.
#' - Creates a pre-release or release branch and bumps the version accordingly.
#' - Writes/updates `cran-comments.md` with useful information about the current
#' release process.
#' - Prompts the user to run `urlchecker::url_update()`, `devtools::check_win_devel()`,
#' and `rhub::check_for_cran()`.
#'
#' `pre_release()`:
#' - Runs `urlchecker::url_update()`, `devtools::check_win_devel()`,
#' and `rhub::rhub_check(platforms = rhub::rhub_platforms()$name)`
#' in the background of the RStudio IDE, or prompts the user to do so.
#' - Opens a pull request for the release branch for final checks.
#'
#' @param which Component of the version number to update. Supported
#' values are
#' * `"next"` (`"major"` if the current version is `x.99.99.9yz`,
#' `"minor"` if the current version is `x.y.99.za`,
#' * `"pre-patch"` (default, `x.y.z.9900`)
#' * `"pre-minor"` (`x.y.99.9900`),
#' * `"pre-major"` (`x.99.99.9900`),
#' * `"next"` (`"major"` if the current version is `x.99.99.9yyy`,
#' `"minor"` if the current version is `x.y.99.9zzz`,
#' `"patch"` otherwise),
#' * `"patch"`
#' * `"minor"`,
#' * `"major"`.
#' @param force Create branches and tags even if they exist.
#' Useful to recover from a previously failed attempt.
#' @name release
#' @rdname release
#' @export
init_release <- function(which = "next", force = FALSE) {
check_main_branch("init_release()")
plan_release <- function(
which = c("pre-patch", "pre-minor", "pre-major", "next", "patch", "minor", "major"),
force = FALSE
) {
check_main_branch("plan_release()")
check_only_modified(character())
check_gitignore("cran-comments.md")
check_suggested(
c("job", "devtools", "rhub", "urlchecker", "pkgbuild", "foghorn"),
"plan_release"
)

stopifnot(which %in% c("next", "patch", "minor", "major", "pre-patch", "pre-minor", "pre-major"))
which <- arg_match(which)
if (which == "next") {
which <- guess_next()
}

local_options(usethis.quiet = TRUE)
with_repo(init_release_impl(which, force))
}

#' @rdname release
#' @export
pre_release <- function(force = FALSE) {
check_cran_branch("pre_release()")

local_options(usethis.quiet = TRUE)
with_repo(pre_release_impl(force))
}

guess_next <- function() {
desc <- desc::desc(file = "DESCRIPTION")
guess_next_impl(desc$get_version())
with_repo(plan_release_impl(which, force))
}

guess_next_impl <- function(version) {
version_components <- get_version_components(version)
if (version_components[["patch"]] == 99) {
if (version_components[["minor"]] == 99) {
which <- "major"
} else {
which <- "minor"
}
} else {
which <- "patch"
}

return(which)
}

init_release_impl <- function(which, force) {
plan_release_impl <- function(which, force) {
# Checking if it's an orphan branch: https://github.com/r-lib/gert/issues/139
stopifnot(get_branch_name() != "HEAD")

# Do we need bump_version() first?
if (!no_change()) {
cli_abort(c(
"Aborting release process because not all changes were recorded.",
i = "Run {.run fledge::bump_version()}, then rerun {.run fledge::init_release()}"
i = "Run {.run fledge::bump_version()}, then rerun {.run fledge::plan_release()}"
))
}

# Check PAT early
check_gh_pat()
check_gh_pat("repo")

fledgeling <- read_fledgling()
new_version <- fledge_guess_version(fledgeling[["version"]], which)
Expand All @@ -93,15 +77,17 @@ init_release_impl <- function(which, force) {
}

if (fledge_chatty()) {
cat(boxx("pre-release", border_style = "double"))
cat(boxx("plan_release", border_style = "double"))
}

# Begin extension points
# End extension points

# Don't bump here, want to be compatible with merge queues at some point

if (fledge_chatty()) cli_h1("1. Creating a release branch and getting ready")
if (fledge_chatty()) {
cli_h1("1. Creating a release branch and getting ready")
}

# regroup dev news
fledgeling <- merge_dev_news(fledgeling, new_version)
Expand All @@ -120,30 +106,15 @@ init_release_impl <- function(which, force) {
edit_news()
edit_cran_comments()

if (fledge_chatty()) {
cli_h1("2. User Action Items")
cli_div(theme = list(ul = list(color = "magenta")))
cli_ul("Run {.run devtools::check_win_devel()}.")
cli_ul("Run {.run rhub::check_for_cran()}.")
cli_ul("Run {.run urlchecker::url_update()}.")
cli_ul("Check all items in {.file cran-comments.md}.")
cli_ul("Review {.file NEWS.md}.")
cli_ul("Run {.run fledge::pre_release()}.")
send_to_console("urlchecker <- urlchecker::url_update(); fledge:::bg_r(winbuilder = devtools::check_win_devel(quiet = TRUE), rhub = rhub::check_for_cran())")
}
}

pre_release_impl <- function(force) {
# check PAT scopes for PR for early abort
check_gh_pat("repo")

check_only_modified(c("NEWS.md", "cran-comments.md"))
gert::git_add(c("NEWS.md", "cran-comments.md"))
if (nrow(gert::git_status(staged = TRUE)) > 0) {
gert::git_commit("NEWS and CRAN comments")
}

cli_h1("1. Opening Pull Request for release branch")
if (fledge_chatty()) {
cli_h1("2. Opening Pull Request for release branch")
}

main_branch <- get_main_branch()
remote_name <- get_remote_name(main_branch)
Expand All @@ -155,20 +126,102 @@ pre_release_impl <- function(force) {
cli_alert("Opening draft pull request with contents from {.file cran-comments.md}.")
}

create_pull_request(get_branch_name(), main_branch, remote_name, force)
has_src <- pkgbuild::pkg_has_src()

# user action items
if (fledge_chatty()) {
cli_h1("2. User Action Items")
cli_div(theme = list(ul = list(color = "magenta")))
cli_ul("Run {.code fledge::release()}.")
cli_end()
if (is_installed("job") && rstudioapi::isAvailable() && !nzchar(Sys.getenv("FLEDGE_TEST_NOGH"))) {
inject(job::empty(title = "create_pull_request", {
asNamespace("fledge")$create_pull_request(!!get_branch_name(), !!main_branch, !!remote_name, !!force)
}))
inject(job::empty(title = "check_win_devel", {
devtools::check_win_devel()
}))
if (has_src) {
inject(job::empty(title = "rhub", {
if (has_src) rhub::rhub_check(platforms = rhub::rhub_platforms()$name, branch = !!release_branch)
}))
}
inject(job::empty(title = "url_update", {
urlchecker::url_update()
}))

if (fledge_chatty()) {
cli_h1("3. User Action Items")
cli_div(theme = list(ul = list(color = "magenta")))
cli_ul("Check all items in {.file cran-comments.md}.")
cli_ul("Review {.file NEWS.md}.")

if (is_dev_version(fledgeling$version)) {
# FIXME: Is this the right code?
cli_ul("Run {.run fledge::finalize_version(push = TRUE)}.")
cli_ul("Merge the PR.")
cli_ul('Restart with {.run fledge::plan_release("next")}.')
} else {
cli_ul("Run {.code fledge::release()}.")
}

cli_end()
}
} else {
create_pull_request(get_branch_name(), main_branch, remote_name, force)

# user action items
if (fledge_chatty()) {
cli_h1("3. User Action Items")
cli_div(theme = list(ul = list(color = "magenta")))
cli_ul("Run {.run devtools::check_win_devel()}.")
if (has_src) cli_ul("Run {.run rhub::rhub_check(platforms = rhub::rhub_platforms()$name, branch = '{release_branch}')}.")
cli_ul("Run {.run urlchecker::url_update()}.")
cli_ul("Check all items in {.file cran-comments.md}.")
cli_ul("Review {.file NEWS.md}.")

url_update_code <- "urlchecker <- urlchecker::url_update()"
winbuilder_code <- "winbuilder = devtools::check_win_devel(quiet = TRUE)"
if (has_src) {
rhub_code <- ", rhub = if (FALSE) rhub::rhub_check(platforms = rhub::rhub_platforms()$name, branch = '{release_branch}')"
} else {
rhub_code <- ""
}
send_to_console(
glue("{url_update_code}; fledge:::bg_r({winbuilder_code}{rhub_code})")
)

if (is_dev_version(fledgeling$version)) {
# FIXME: Is this the right code?
cli_ul("Run {.run fledge::finalize_version(push = TRUE)}.")
cli_ul("Merge the PR.")
cli_ul('Restart with {.run fledge::plan_release("next")}.')
} else {
cli_ul("Run {.code fledge::release()}.")
}

cli_end()
}
}

# Begin extension points
# End extension points
}

guess_next <- function() {
desc <- desc::desc(file = "DESCRIPTION")
guess_next_impl(desc$get_version())
}

guess_next_impl <- function(version) {
version_components <- get_version_components(version)
if (version_components[["patch"]] == 99) {
if (version_components[["minor"]] == 99) {
which <- "major"
} else {
which <- "minor"
}
} else {
which <- "patch"
}

return(which)
}

get_branch_name <- function() {
gert::git_branch()
}
Expand Down Expand Up @@ -219,7 +272,7 @@ check_release_branch <- function(new_version) {
if (gert::git_branch_exists(branch_name)) {
cli_abort(c(
x = "The branch {.val {branch_name}} already exists.",
i = "Do you need {.code init_release(force = TRUE)}?"
i = "Do you need {.code plan_release(force = TRUE)}?"
))
}
}
Expand Down Expand Up @@ -761,3 +814,9 @@ extract_version_pr <- function(title) {
matches <- regexpr("[0-9]*\\.[0-9]*\\.[0-9]*", title)
regmatches(title, matches)
}

no_change <- function(ref = "HEAD") {
# Only review meaningful comments
news <- collect_news(default_commit_range(ref), no_change_message = NA_character_)
NROW(news) == 0
}
6 changes: 0 additions & 6 deletions R/bump-version.R
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,3 @@ get_main_branch_config <- function(repo) {
return(init[init$level == "global", ]$value)
}
}

no_change <- function(ref = "HEAD") {
# At most, one commit from the latest bump_version() run
# FIXME: Should be <= 0?
nrow(default_commit_range(ref)) <= 1
}
Loading

0 comments on commit 9c6d74c

Please sign in to comment.