Title: | Smoother Change Tracking and Versioning for R Packages |
---|---|
Description: | Streamlines the process of updating changelogs (NEWS.md) and versioning R packages developed in git repositories. |
Authors: | Kirill Müller [aut, cre, cph] , Patrick Schratz [aut] , Maëlle Salmon [ctb] |
Maintainer: | Kirill Müller <[email protected]> |
License: | GPL-3 |
Version: | 0.1.99.9037 |
Built: | 2024-12-26 01:17:42 UTC |
Source: | https://github.com/cynkra/fledge |
Calls the following functions:
Verify that the current branch is the main branch
if check_default_branch = TRUE
(the default).
update_news()
, using the which
argument, applying logic to determine
if meaningful changes have been made since the last version.
From the result, check if there were meaningful changes since the last version.
Depending on the which
argument:
If "dev"
, finalize_version()
with push = FALSE
Otherwise, commit_version()
.
bump_version( which = c("dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major"), ..., no_change_behavior = c("bump", "noop", "fail"), check_default_branch = TRUE )
bump_version( which = c("dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major"), ..., no_change_behavior = c("bump", "noop", "fail"), check_default_branch = TRUE )
which |
Component of the version number to update. Supported values are
|
... |
These dots are for future extensions and must be empty. |
no_change_behavior |
What to do if there was no change since the last
version: |
check_default_branch |
Whether to check that the current branch is the default branch. |
TRUE
if NEWS.md
and DESCRIPTION
have been updated,
FALSE
otherwise.
Do not rely on this behavior.
Have you just run bump_version()
, then realized
"oh shoot, I forgot to merge that PR"?
Fear not, run unbump_version()
, merge that PR, run bump_version()
.
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() })
Commits changes to NEWS.md
and DESCRIPTION
, amending a previous commit
created by fledge if necessary.
commit_version()
commit_version()
Invisibly: TRUE
if a previous commit for that version has been
amended, FALSE
if not.
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() desc::desc_add_author(given = "Jane", family = "Doe", role = "ctb") fledge::commit_version() })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() desc::desc_add_author(given = "Jane", family = "Doe", role = "ctb") fledge::commit_version() })
Create example repo for fledge demos
create_demo_project( open = rlang::is_interactive(), name = "tea", maintainer = NULL, email = NULL, date = "2021-09-27", dir = file.path(tempdir(), "fledge"), news = FALSE )
create_demo_project( open = rlang::is_interactive(), name = "tea", maintainer = NULL, email = NULL, date = "2021-09-27", dir = file.path(tempdir(), "fledge"), news = FALSE )
open |
Whether to open the new project. |
name |
Package name. |
maintainer |
Name for DESCRIPTION and git. |
email |
Email for DESCRIPTION and git. |
date |
String of time for DESCRIPTION and git. |
dir |
Directory within which to create the mock package folder. |
news |
If TRUE, create a NEWS.md file. |
The path to the newly created mock package.
Calls the following functions:
tag_version()
with force = TRUE
Force-pushes the created tag to the "origin"
remote, if push = TRUE
.
finalize_version(push = FALSE)
finalize_version(push = FALSE)
push |
If |
None
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() # Edit news by hand # ... # Once done fledge::finalize_version() })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() # Edit news by hand # ... # Once done fledge::finalize_version() })
Returns the most recent Git tag that is reachable from the current branch.
This will not be accurate if the version bump and tag has occurred on a branch
which has been squashed into the main branch.
See get_last_version_tag()
for a version that works in this scenario.
get_last_tag()
get_last_tag()
A one-row tibble with columns name
, ref
and commit
.
For annotated tags (as created by fledge), commit
may be different
from the SHA of the commit that this tag points to.
Use gert::git_log()
to find the actual commit.
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::finalize_version() print(get_top_level_commits(since = NULL)) print(fledge::get_last_tag()) })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::finalize_version() print(get_top_level_commits(since = NULL)) print(fledge::get_last_tag()) })
Returns the Git tag of the form vx.y, vx.y.z or vx.y.z.w with the latest version.
An older version of this logic is used in get_last_tag()
,
which traverses the Git history but does not work with squash-merging of version bumps.
get_last_version_tag()
get_last_version_tag()
A one-row tibble with columns name
, ref
and commit
.
For annotated tags (as created by fledge), commit
may be different
from the SHA of the commit that this tag points to.
Use gert::git_log()
to find the actual commit.
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Switch to branch for bumping version. gert::git_branch_create("fledge") # Bump version with fledge. fledge::bump_version(check_default_branch = FALSE) fledge::finalize_version() # Merge the version bump branch into main. gert::git_branch_checkout("main") gert::git_merge("fledge", squash = TRUE) print(get_top_level_commits(since = NULL)) # get_last_tag() doesn't work in this scenario print(fledge::get_last_tag()) # get_last_version_tag() is better print(fledge::get_last_version_tag()) })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Switch to branch for bumping version. gert::git_branch_create("fledge") # Bump version with fledge. fledge::bump_version(check_default_branch = FALSE) fledge::finalize_version() # Merge the version bump branch into main. gert::git_branch_checkout("main") gert::git_merge("fledge", squash = TRUE) print(get_top_level_commits(since = NULL)) # get_last_tag() doesn't work in this scenario print(fledge::get_last_tag()) # get_last_version_tag() is better print(fledge::get_last_version_tag()) })
Return all top-level commits since a particular version as commit objects.
get_top_level_commits(since = NULL)
get_top_level_commits(since = NULL)
since |
A commit SHA, e.g. as returned in the |
A tibble::tibble with at least two columns:
commit
: the commit SHA
message
: the commit message
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::finalize_version() print(get_top_level_commits(since = NULL)) print(fledge::get_last_tag()) })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::finalize_version() print(get_top_level_commits(since = NULL)) print(fledge::get_last_tag()) })
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.
release()
sends to CRAN after performing several checks,
and offers help with accepting the submission.
post_release()
should be called after the submission has been accepted.
plan_release( which = c("pre-patch", "pre-minor", "pre-major", "next", "patch", "minor", "major"), force = FALSE ) release() post_release()
plan_release( which = c("pre-patch", "pre-minor", "pre-major", "next", "patch", "minor", "major"), force = FALSE ) release() post_release()
which |
Component of the version number to update. Supported values are
|
force |
Create branches and tags even if they exist. Useful to recover from a previously failed attempt. |
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.
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.
Parses NEWS.md
and creates/updates the tag for the most recent version.
tag_version(force = FALSE)
tag_version(force = FALSE)
force |
Re-tag even if the last commit wasn't created by
|
The created tag, invisibly.
None
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::update_news(c("- something I forgot", "- blabla"), which = "patch") gert::git_add("NEWS.md") gert::git_commit(message = "release notes tweaking") fledge::tag_version() print(fledge::get_last_version_tag()) })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::update_news(c("- something I forgot", "- blabla"), which = "patch") gert::git_add("NEWS.md") gert::git_commit(message = "release notes tweaking") fledge::tag_version() print(fledge::get_last_version_tag()) })
This undoes the effect of a bump_version()
call, with a safety check.
unbump_version()
unbump_version()
NULL
, invisibly. This function is called for its side effects.
None
bump_version
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() # Oh no, we forgot to also add the awesome function for that version! # UNBUMP fledge::unbump_version() # Add a new R file. usethis::use_r("awesome-function", open = FALSE) # Pretend we added awesome code inside it. # Track the new R file with Git. gert::git_add("R/awesome-function.R") gert::git_commit("- Add awesome function.") # Bump version with fledge. fledge::bump_version() #' })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() # Oh no, we forgot to also add the awesome function for that version! # UNBUMP fledge::unbump_version() # Add a new R file. usethis::use_r("awesome-function", open = FALSE) # Pretend we added awesome code inside it. # Track the new R file with Git. gert::git_add("R/awesome-function.R") gert::git_commit("- Add awesome function.") # Bump version with fledge. fledge::bump_version() #' })
Lists all commits from a range (default: top-level commits since the most
recent tag as determined by get_last_version_tag()
)
and adds bullets from their body to NEWS.md
.
Creates NEWS.md
if necessary.
update_news( messages = NULL, which = c("auto", "samedev", "dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major") )
update_news( messages = NULL, which = c("auto", "samedev", "dev", "pre-patch", "patch", "pre-minor", "minor", "pre-major", "major") )
messages |
A character vector of commit messages,
e.g. as in the |
which |
Component of the version number to update. Supported values are
|
None
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::update_news(c("- something I forgot", "- blabla"), which = "patch") gert::git_add("NEWS.md") gert::git_commit(message = "release notes tweaking") fledge::tag_version() print(fledge::get_last_version_tag()) })
# Create mock package in a temporary directory. # Set open to TRUE if you want to play in the mock package. with_demo_project({ # Use functions as if inside the newly created package project. # (Or go and actually run code inside the newly created package project!) # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() fledge::update_news(c("- something I forgot", "- blabla"), which = "patch") gert::git_add("NEWS.md") gert::git_commit(message = "release notes tweaking") fledge::tag_version() print(fledge::get_last_version_tag()) })
Run code in temporary project
with_demo_project(code, dir = NULL, news = TRUE, quiet = FALSE) local_demo_project( dir = NULL, news = TRUE, quiet = FALSE, .local_envir = parent.frame() )
with_demo_project(code, dir = NULL, news = TRUE, quiet = FALSE) local_demo_project( dir = NULL, news = TRUE, quiet = FALSE, .local_envir = parent.frame() )
code |
Code to run with temporary active project |
dir |
Directory within which to create the mock package folder. |
news |
If TRUE, create a NEWS.md file. |
quiet |
Whether to show messages from usethis |
.local_envir |
The environment to use for scoping. Defaults to current execution environment. |
with_demo_project()
returns the result of evaluating code
.
local_demo_project()
is called for its side effect and returns NULL
, invisibly.
with_demo_project({ # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() })
with_demo_project({ # Add a new R file. usethis::use_r("cool-function", open = FALSE) # Pretend we added useful code inside it. # Track the new R file with Git. gert::git_add("R/cool-function.R") gert::git_commit("- Add cool function.") # Bump version with fledge. fledge::bump_version() })