forked from hadley/r-pkgs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrelease.rmd
More file actions
505 lines (353 loc) · 25.9 KB
/
release.rmd
File metadata and controls
505 lines (353 loc) · 25.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
---
title: Releasing a package
layout: default
output: bookdown::html_chapter
---
# Releasing a package {#release}
If you want your package to have significant traction in the R community, you need to submit it to CRAN. Submitting to CRAN is a lot more work than just providing a version on github, but the vast majority of R users do not install packages from github. The CRAN submission process can be frustrating, but it's worthwhile, and this chapter will make it as painless as possible.
To get your package ready to release, follow these steps:
1. Pick a version number.
1. Run and document `R CMD check`.
1. Check that you're aligned with CRAN polices.
1. Update `README.md` and `NEWS.md`.
1. Submit the package to CRAN.
1. Prepare for the next version.
1. Publicise the new version.
## Version number {#release-version}
If you've been following the advice in [versioning](#version), the version number of your in-development package will have four components, `major.minor.patch.dev` (where `dev` is at least 9000). Released packages don't have a `dev` component, so now you need to drop that and pick a version number based on the changes you've made. For example, if the current version is `0.8.1.9000` will the next version be `0.8.2`, `0.9.0` or `1.0.0`? Use this advice to decide:
* Increment `patch`, e.g. `0.8.2` for a __patch__: you've fixed
bugs without adding significant new features. I'll often do a patch release
if after release I discover a show-stopping bug that needs to be fixed
ASAP.
* Increment `minor`, e.g. `0.9.0`, for a __minor release__. A minor
release can include bug fixes, new features and backward compatible changes.
This is the most common type of release. It's perfectly fine to have so
many minor releases that you need to use two digits, e.g. `1.17.0`.
* Increment `major`, e.g. `1.0.0`, for a __major release__. This is
best reserved for backward incompatible changes that are likely to affect
many users. Going from `0.b.c` to `1.0.0` typically indicates that your
package is feature complete with a stable API.
In practice, backward compatibility is not discrete, but continuous. For
example, if you make an API-incompatible change to a rarely-used part of
your code, it may not deserve a major number change. If you fix a bug that
many people are depending on, it will feel like an API breaking change.
Use your best judgement.
### Backward compatibility
The big different between major and minor versions is whether or not the code is backward compatible. This difference tends to be a bit academic in the R community because the way most people update packages is by running `update.packages()`. `update.packages()` always updates to the latest version of the package, even if the major version has changed, potentially breaking code. While more R users are becoming familiar with tools like [packrat](http://rstudio.github.io/packrat/) which capture package versions on a per-project basis, you do need to be a little cautious when making big backward incompatible changes, regardless of what you do with the version number.
The importance of backward compatability is directly proportional to the number of people using your package because you are trading your time for your users time. The harder you strive to be backward compatible, the harder it is to develop new features or fix old mistakes. Backward compatible code tends to be harder to read because it requires multiple paths to support functionality from previous versions. Be concerned about backward compatibility, but don't let it paralyse you.
There are good reasons to make backward incompatible changes - if you made a design mistake that makes your package harder to use it's better to fix it sooner rather than later. If you do need to make a backward incompatible, it's best to do it gradually. You need an interim version between the where are you now and the ideal implementation that provides advice about what's changing. Depending on what you're changing, use one of the following techniques to let your users know what's happening:
* Don't immediately remove a function. First deprecate it. For example, imagine
your package is version `0.5.0` and you want to remove `fun()`. In
version, `0.6.0`, you'd use `.Deprecated()` to display a warning message
whenever someone uses the function:
```{r}
# 0.1.0
fun <- function(x, y, z) {
.Deprecated("sum")
x + y + z
}
```
Then you'd remove the function once you got to `0.7.0` (or if you were
being very strict, once you got to `1.0.0` since it's a backward
incompatible change).
* Similarly, if you're removing a function argument, first warn about it:
```{r}
bar <- function(x, y, z) {
if (!missing(y)) {
warning("argument y is deprecated; please use z instead.",
call. = FALSE)
z <- y
}
}
```
* If you're deprecating a lot of code, it can be useful to add a helper
function. For example, ggplot2 has `gg_dep` which automatically
displays a message, warning or error, depending on how much the version
number has changed.
```{r}
gg_dep <- function(version, msg) {
v <- as.package_version(version)
cv <- packageVersion("ggplot2")
# If current major number is greater than last-good major number, or if
# current minor number is more than 1 greater than last-good minor number,
# give error.
if (cv[[1,1]] > v[[1,1]] || cv[[1,2]] > v[[1,2]] + 1) {
stop(msg, " (Defunct; last used in version ", version, ")",
call. = FALSE)
# If minor number differs by one, give warning
} else if (cv[[1,2]] > v[[1,2]]) {
warning(msg, " (Deprecated; last used in version ", version, ")",
call. = FALSE)
# If only subminor number is greater, give message
} else if (cv[[1,3]] > v[[1,3]]) {
message(msg, " (Deprecated; last used in version ", version, ")")
}
invisible()
}
```
* Significant changes to an existing function will require planning and may
require gradual changes over multiple versions. Try and develop a sequence
of transformations where each change can be accompanied by an informative
error message.
* If you want to use functionality in a new version of another package,
don't make it a hard install-time dependency in the `DESCRIPTION` (because
forcing your users to upgrade that package might break other code). Instead
check for the version at run-time:
```{r}
if (packageVersion("ggplot2") < "1.0.0") {
stop("ggplot2 >= 1.0.0 needed for this function.", call. = FALSE)
}
```
This is also useful if you're responding to changes in one of your
dependencies - you'll want to have a version that works both before
and after the change so you can submit it to CRAN before the other
package is, and it will work both before and after. Doing this may
generate some `R CMD check` notes. For example:
```{r, eval = FALSE}
if (packageVersion("foo" > "1.0.0")) {
foo::baz()
} else {
foo:bar()
}
```
If `baz` doesn't exist in foo version 1.0.0, you'll get a note that
it doesn't exist in foo's namespace. Just explain that you're working
around an difference between versions in your submission to CRAN.
## The check process {#release-check}
You've already learned how to use `R CMD check` and why it's important in [automated checking](#check). Compared to running `R CMD check` locally, there are a few important differences when running it for CRAN submission:
* You __must__ eliminate all `ERROR`s and `WARNING`s. You __should__ eliminate
as many `NOTE`s as possible. Each `NOTE` requires human oversight, which is a
precious commodity. If there are notes that you do not believe are important,
it is almost always easier to fix them (even if the fix is a bit of a hack)
than to persuade CRAN that they're ok.
* You need to document your process and clearly communicate the results to CRAN.
Write your comments in way that's easy to scan, and easy to match up with
`R CMD check`. Provide the CRAN maintainers with everything they need in
one place, even if it means repeating yourself.
* You need to check the package with R-devel, and on at least two platforms.
See [R-devel](#release-r-devel) and [Cross platform](#release-cross-platform)
for more details.
* If there are CRAN packages that use your package, you need to run
`R CMD check` on all those packages, and summarise the results. See
[reverse dependency checks](#release-deps) for the details.
CRAN is staffed by volunteers and they all have other full-time jobs. In a typical week, CRAN recieves around 130 packages, and there are only three volunteers to process them all. The less work you make for them the more likely you are to have a pleasant submission experience.
I recommend that you use `cran-comments.md` file to document your process. `cran-comments.md` should be checked into git (so you can track it over time), and listed in `.Rbuildignore` (so it's not included in the package). As the extension suggests, I recommend using markdown because it gives a standard way of laying out plain text. However, the contents will never be rendered to another format, so you don't need to worry about sticking to it too closely.
Here are the `cran-comments.md` from a recent version of httr:
```md
## Test environments
* local OS X install, R 3.1.2
* ubuntu 12.04 (on travis-ci), R 3.1.2
* win-builder (devel and release)
## R CMD check results
There were no ERRORs or WARNINGs.
There was 1 NOTE:
* checking dependencies in R code ... NOTE
Namespace in Imports field not imported from: 'R6'
R6 is a build-time dependency.
## Downstream dependencies
I have also run R CMD check on downstream dependencies of httr (https://github.com/wch/checkresults/blob/master/httr/r-release). All packages that I could install passed except:
* Ecoengine: this appears to be a failure related to config on that machine,
I couldn't reproduce locally, and it doesn't seem to be related to changes
in httr (the same problem exists with httr 0.4).
```
It's designed to be easy to skim, and easy to match up to the local `R CMD check` results seen by CRAN maintainers. I always include three sections:
1. Test environments: this describes where I checked the package. I always
check on three platforms: my mac, [travis-ci](#travis) and win-builder.
1. Check results: I always state that there were no errors or warnings.
Any `NOTE`s go in a bulleted list. For each `NOTE`, I include the message
from `R CMD check` and a brief description of why I think it's ok.
If there were not `NOTE`s, I'd say "There were no ERRORs, WARNINGs or NOTEs"
1. Downstream dependencies: If there are downstream dependencies, I run
`R CMD check` on each package and summarise the results. If there are
no downstream dependencies, keep this section, but say: "There are currently
no downstream dependencies of this package".
### R-devel {#release-r-devel}
`R CMD check` is continuously evolving, so it's a good idea to check your package with the latest development version, __R-devel__. You can install R-devel on your own machine:
* Mac: install from <http://r.research.att.com>.
* Windows: install from <http://cran.r-project.org/bin/windows/base/rdevel.html>
* Linux: either build it from source, or better, learn about docker containers
and run the R-devel container from <https://github.com/rocker-org/rocker>.
But it's painful to manage multiple R versions, especially since you'll need to reinstall all your packages. Instead, you can run `R CMD check` on CRAN's servers, as described next.
### Cross-platform checking {#release-cross-platform}
As well as running R-devel, CRAN runs R on multiple platforms: Windows, OS X, Linux and Solaris. Generally, you don't need to run `R CMD check` yourself on every one of these platforms, but it's a really good idea to do it on at least two to increase your chances of spotting code that relies on the idiosyncracries of a specific platform.
To run checks on Windows, use `devtools::build_win()`. This builds your package and submits it to the CRAN win-builder. 10-20 minutes after submission, you'll recieve an email telling you the check results. This will run `R CMD check` on both released and development versions of R. It's a good way to check that your package works with the latest R-devel, without having to install it locally.
To run checks on Linux, I recommend using travis, as described in [continuous integration with Travis](#travis).
Debugging code that works on your computer but fails elsewhere is painful. I recommend either installing a virtualisation tool so that you can run another operating system locally, or find a friend to help you figure out the problem.
### Checking dependencies {#release-deps}
If you're releasing a new version of an existing package, it's your responsibility to check that downstream dependencies (i.e. all packages that list your package in the `Depends`, `Imports`, `Suggests` or `LinkingTo` fields) continue to work. To help you do this, devtools provides `devtools::revdep_check()`. This:
1. Sets up a temporary library so it doesn't clobber any existing packages you
have installed.
1. Installs all of the dependencies of the downstream dependencies.
1. Runs `R CMD check` on each package.
1. Summarises the results in a single file.
If any packages fail `R CMD check`, you should give package authors at least two weeks to fix the problem before you submit your package to CRAN (you can easily get all maintainer email addresses with `revdep_maintainers()`). After the two weeks is up, re-run the checks, and list any remaining failures in `cran-comments.md`. Each package should be accompanied by a brief explanation: either tell CRAN that it's a false positive in `R CMD check` (e.g. you couldn't install a dependency locally) or a legitimate change in the API (which the maintainer hasn't fixed yet).
Inform CRAN of your release process: "I advised all downstream packages maintainers of these problems two weeks ago". Here's an example from a recent release of dplyr:
```
Important reverse dependency check notes (summary at https://github.com/wch/checkresults/blob/master/dplyr/r-release/00check-summary.txt);
* COPASutils, freqweights, qdap, simPH: fail for various reasons. All package
authors were informed of the upcoming release and shown R CMD check issues
over a week ago.
* ecoengine: same problem as always on our test machine.
* ggvis: You'll be recieving a submission that fixes these issues very shortly
from Winston.
* repra, rPref: uses a deprecated function.
```
## CRAN policies {#cran-policies}
As well as the automated checks provided by `R CMD check`, there are a number of [CRAN policies](http://cran.r-project.org/web/packages/policies.html) that must be checked manually. The CRAN maintainers will typically look at this most closely on the first submission of your package.
I've summarised the most common problems below:
* It is vital that maintainer email address is stable. This is the only way
that CRAN has to contact you, and they will remove your package from CRAN
if there are problems and they can't get in touch with. Make sure it's
something that's likely to be around for a while, and that it's not heavily
filtered.
* You must have clearly identified the copyright holders in `DESCRIPTION`:
if you have included external source code, you must ensure that the license
is compatible. See [license](#license) and [`src/` licensing](#src-licensing)
for more details.
* You must "make all reasonable efforts" to get your package working across
multiple platforms, and packages that don't work on at least two will
not normally be considered.
* Do not make external changes without explicit user permission. Don't write to
the file system, change options, install packages, quit R, send information
over the internet, open external software, etc.
* Do not submit updates too frequently. The policy suggests a new version
once every 1-2 months at most.
I recommending following the [CRAN Policy Watch](https://twitter.com/CRANPolicyWatch) twitter account which tweets whenever the policies change. You can also look at the github repository that powers it: <https://github.com/eddelbuettel/crp/commits/master/texi>.
## Important files {#important-files}
You now have a package that's ready to submit to CRAN. But before you do, there are two important files that you should update: `README.md` which describes what the package does, and `NEWS.md` which describes what's changed since the previous version. I recommend using markdown for these files, because it's useful for them to be readable in plain text (e.g. in emails) and in html (e.g. on github, in blog posts). I recommend using Github flavoured markdown, <https://help.github.com/articles/github-flavored-markdown/>, for these files.
### README.md {#readme}
The goal of the `README.md` is to answer the following questions about your package:
* Why should I use it?
* How do I use it?
* How do I get it?
On github, the `README.md` will be rendered as html and displayed on the repository home page.
I normally structure my `README` as follows:
1. A paragraph that describes the high-level purpose of the package.
1. An example showing how to use the package to solve a simple problem.
1. Installation instructions, giving code that can be copied and pasted in R.
1. An overview that describes the main components of the package. For more
complex packages, this will point to vignettes for more details.
### README.Rmd {#readme-rmd}
If you include an example in your `README` (a good idea!) you may want to generate it with Rmarkdown. The easiest way to get started is to use `devtools::use_readme_rmd()`. This creates a template `README.Rmd` and adds it to `.Rbuildignore`. The template looks like:
---
output:
md_document:
variant: markdown_github
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, echo = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "README-"
)
```
This:
* Oututs Github flavoured markdown.
* Includes a comment in `README.md` to remind you to edit `README.Rmd`, not
`README.md`.
* Sets up my recommend knitr options, including saving an images to
`README-chunkname.png` (which is automatically `.Rbuildignore`d.)
You'll need to remember to re-knit `README.Rmd` each time you modify it. If you use git, `use_readme_rmd()` automatically adds the following "pre-commit" hook:
```bash
#!/bin/bash
if [[ README.Rmd -nt README.md ]]; then
echo "README.md is out of date; please re-knit README.Rmd"
exit 1
fi
```
This prevents `git commit` from succeeding unless `README.md` is more recent than `README.Rmd`. If you get a false positive, you can ignore the check with `git commit --no-verify`. Note that git commit hooks are not stored in the repository, so every time you check out the repo, you'll need to run `devtools::use_readme_rmd()` to set it up again.
### NEWS.md {#news}
The `README.md` is aimed at new users. The `NEWS.md` is aimed at existing users: it should list all changes in each release. There are a number formats you can use for package news, but I recommend `NEWS.md`. It's not supported by CRAN (so you'll need to run `devtools::add_build_ignore("NEWS.md")`), but it's well supported by github and is easy to re-purpose to other formats.
Organise your `NEWS.md` as follows:
* Use a top-level heading for each version: e.g. `# mypage 1.0`. The most
recent version should go at the top.
* Each change should be included in a bulleted list. If you have a lot of
changes you might want to break them up using subheadings, `## Major changes`,
`## Bug fixes` etc. I usually stick with a simple list until just before
releasing the package when I'll reorganise into sections, if needed.
It's hard to know in advance exactly what sections you'll need.
* If an item is related to an issue in github, include the issue number in
parentheses, e.g. `(#10)`. If an item is related to a pull request, include
the pull request number and the author, e.g. `(#101, @hadley)`. Doing
this makes it easy to navigate to the relevant issues on github.
The main challenge with `NEWS.md` is getting into the habit of noting each change as you do it.
## Release {#release-submission}
You're now ready to submit your package to CRAN. The easiest way to do this is to run `devtools::release()`. This:
* Builds the package and runs `R CMD check` one last time.
* Asks you a number of yes/no questions to verify that your followed the
most common best practices.
* You can add your own questions to the check process by including an
unexpected `release_questions()` function in your package. This should
return a character vector of questions to ask. For example, httr has:
```{r}
release_questions <- function() {
c(
"Have you run all the OAuth demos?",
"Is inst/cacert.pem up to date?"
)
}
```
This is useful for reminding you to do any manual tasks that
can't otherwise be automated.
* Submits the package to the
[CRAN submission form](http://cran.r-project.org/submit.html) including the
comments in `cran-comments.md`.
Within the next few minutes, you'll recieve a email notifying you of the submission and asking you to approve it (this confirms that the maintainer address is correct). Next the CRAN maintainers will run their checks and get back to you with the results. This normally takes around 24 hours, but occassionally can take up to 5 days.
### On failure
If your package does not pass `R CMD check` or is inviolation of one of the CRAN policies, a CRAN maintainer will email you and describe the problems. Failures are frustrating, and the feedback may be curt or downright insulting. Arguing with CRAN maintainers is fruitless. Instead:
* Breathe. A rejected CRAN package is not the end of the world. It happens to
everyone. Even members of R-core have to go through the same process and CRAN
is no friendlier to them. I have had numerous packages rejected by CRAN.
I was banned from submitting to CRAN for two weeks because too many of
my existing packages had minor problems.
* If the response gets you really riled up, take a couple of days to cool down
before responding. Ignore any ad hominen attacks, and strive to respond only
to the technical content.
* If a devtools problem causes a CRAN maintainer to be annoyed with you, I
am deeply sorry and if you forward me the message along with your address,
I'll send you a hand-written apology card.
Unless you feel extremely strongly that discussion is merited, don't respond to the email. Instead:
* Fix the identified problems and make recommended changes. Re-run
`devtools::check()` to make sure you didn't accidentally introduce any
new problems.
* Add a "Resubmission" section at the top of `cran-comments.md`. This should
clearly identify that the package is a resubmission, and list the changes
that you made.
```md
## Resubmission
This is a resubmission. In this version I have:
* Converted the DESCRIPTION title to title case.
* More clearly identified the copyright holders in the DESCRIPTION
and LICENSE files.
```
* If necessary, update the check results and downstream dependencies sections.
* Run `devtools::submit_cran()` to re-submit the package without working
through all the `release()` questions a second time.
### Binary builds
After the package has been accepted by CRAN it will be built for each platform. It's possible this may uncover further errors. Wait 48 hours until all the checks for all packages have been run, then go to the check results package for your package:
```{r, echo = FALSE}
bookdown::embed_png("screenshots/cran-checks.png", dpi = 220)
```
Prepare a patch release that fixes the problems and submit using the same process as above.
## Prepare for next version {#post-release}
Once your package has been accepted by CRAN, you have a couple of technical operations to do:
* If you use github, go to the repository release page. Create a new release
with tag version `v1.2.3` (i.e. "v" followed by the version of your package).
Copy and paste the contents of the relevant `NEWS.md` section into the release
notes.
* If you use git, but not github, tag the release with `git tag -a v1.2.3`.
* Add the `.9000` prefix to the `Version` field in the DESCRIPTION to indicate
that this is once more a development version. Create a new heading in
`NEWS.md`.
## Promotion {#promotion}
Now you're ready for the fun part: publicising your package. This is really important: no one will use your helpful new package if they don't know that it exists.
Start by writing a release announcement. This should be an Rmarkdown document that briefly describes what the package does (so people who haven't used it before can understand why they might care), and what's new in this version. Start with the contents of `NEWS.md`, but you'll need to considerably modified it. The goal of `NEWS.md` is to be comprehensive; the goal of the release announcement is to highlight the most important changes. Include a link at the end of the announcement to the full release notes so people can see all the changes. Where possible, I recommend showing examples of the new features: it's much easier to understand the benefit of a new feature if you can see it in action.
There are a number of places you can include the announcement:
* If you have a blog, publish it there. I now publish all package release
announcements on the [RStudio blog](http://blog.rstudio.org/author/hadleywickham/).
* If you use twitter, tweet about it.
* Send it to the
[r-packages mailing list](https://stat.ethz.ch/mailman/listinfo/r-packages).
Messages sent to this list are automatically forwarded to the R-help mailing
list.