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.9036 |
Built: | 2024-12-12 01:25:01 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.
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() })