Skip to content

Commit

Permalink
Revisions to pr_*() article
Browse files Browse the repository at this point in the history
  • Loading branch information
jennybc committed Jul 5, 2019
1 parent d6a8a82 commit 4053147
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 100 deletions.
187 changes: 89 additions & 98 deletions vignettes/articles/pr-functions.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,31 @@ div.reviewer pre.r { background-color:#e3dece; }
div.output pre.r { background-color:#FFFFFF; }
</style>

The `pr_*` family of functions is designed to make working with GitHub [pull requests](https://help.github.com/en/articles/about-pull-requests)
as painless as possible for both contributors and package maintainers. They are
designed to support the Git and GitHub best practices described in
[Happy Git and GitHub for the useR](http://happygitwithr.com/).
## Contributing to someone else's package

So, you want to contribute to an R package? That's fantastic!

Here we walk through the process of making a so-called **pull request** to the [praise](https://github.com/rladies/praise) package. This package is designed to help package developers "build friendly R packages that praise their users if they have done something good, or they just need it to feel better." You can use praise to construct encouraging feedback by sampling from its collection of positive adjectives, adverbs, verbs, smileys, and exclamations:

This vignette will walk you through a contribution to an R package via a pull
request.
```{r eval = FALSE}
library(praise)
template <- "${EXCLAMATION} - your pull request is ${adjective}!"
praise(template)
#> [1] "YEE-HAW - your pull request is groovy!"
```

A pull request (PR) involves two players, a contributor and a reviewer.
In an effort to help keep straight who runs which code, the code chunks in this
vignette are color coded: code by contributor appears in chunks with light gray
background and code by reviewer appears in chunks with beige background.
We are going to propose a new exclamation: "yeah-yah".

## What's a pull request?

A [pull request](https://help.github.com/en/articles/about-pull-requests) is how you propose a change to a GitHub repository. Think of it as a _request_ for the maintainer to _pull_ your changes into their repo.

The `pr_*()` family of functions is designed to make working with GitHub pull requests as painless as possible, for both contributors and package maintainers. They are designed to support the Git and GitHub workflows recommended in
[Happy Git and GitHub for the useR](http://happygitwithr.com/).

A pull request (PR) involves two players, a contributor and a reviewer. To make it more clear who runs which code, the code chunks in this article are color coded: code executed by the contributor appears in chunks with light gray background and code executed by the reviewer appears in chunks with beige background.

```{r sample_contributor, eval=FALSE}
# contributor code
Expand All @@ -34,68 +47,62 @@ background and code by reviewer appears in chunks with beige background.
```
</div>

This vignette assumes that you have already gone through the
[setup vignette](/articles/articles/usethis-setup). A good way to check that
you are ready to use the `pr_*` family of functions is to run
`usethis::git_sitrep()`, which prints info about your current Git, git2r,
and GitHub setup.

## Set up advice

These functions make heavy use of git2r and the GitHub API. You'll need a GitHub
personal access token (PAT); see `browse_github_token()` for help with that. If
git2r does not seem to be finding your git credentials, read `git_credentials()`
for troubleshooting advice. The transport protocol (SSH vs HTTPS) is determined
from the existing remote URL(s) of the repo.
This article assumes that you have already done the Git and GitHub parts of the [setup vignette](/articles/articles/usethis-setup). A good way to check that you are ready to use the `pr_*` family of functions is to run `git_sitrep()`, which prints info about your current Git, git2r, and GitHub setup.

## Contributing via a pull request
Specifically, the `pr_*()` functions make use of:

So, you want to contribute to an R package? That's fantastic!

In this vignette we'll walk through the process of making a pull request to the
[**praise**](https://github.com/rladies/praise) package. This package is
designed to help package developers _"build friendly R packages that praise their
users if they have done something good, or they just need it to feel better."_
The package contains a series of positive adjectives, adverbs, verbs, smileys,
and exclamations. In our pull request we will propose adding a new exclamation:
"yeah-yah".
* The GitHub API, which requires a personal access token (PAT).
- `browse_github_token()` helps you set one up.
* git2r, an R package which does git operations from R.
- See the help for `git_credentials()` if git2r doesn't seem to find your git credentials.
* Your preferred git transport protocol: `"ssh"` or `"https"`.
- If usethis can't figure this out, it might ask you. You can set the
`usethis.protocol` option to proactively address this.

### Fork and clone
## Fork and clone

The first step is to fork the source repository, and then check out a local
copy. There are two ways you can do this, one is on GitHub by clicking on Fork,
and the other is using `usethis::create_from_github`. We will focus on the latter.

If you have not previously contributed to this repository, chances are you have
not forked it previously either. To first fork, and then clone your fork, use
`usethis::create_from_github()` with the `fork` argument set to `TRUE`.
The first step is to fork the source repository, to get your own copy on GitHub, and then clone that, to get your own local copy. There are many ways to accomplish these two steps, but here we demonstrate `usethis::create_from_github()`:

```{r create_from_github, eval=FALSE}
create_from_github(repo_spec = "rladies/praise", fork = TRUE)
create_from_github("rladies/praise")
```
<div class = "output">
```{r eval=FALSE}
#> ✔ Creating '/Users/mine/Desktop/praise/'
#> ✔ Forking 'rladies/praise'
#> ✔ Cloning repo from '[email protected]:mine-cetinkaya-rundel/praise.git' into # '/Users/mine/Desktop/praise'
#> ✔ Cloning repo from '[email protected]:mine-cetinkaya-rundel/praise.git' into '/Users/mine/Desktop/praise'
#> ✔ Setting active project to '/Users/mine/Desktop/praise'
#> ✔ Adding 'upstream' remote: '[email protected]:rladies/praise.git'
#> ✔ Pulling changes from GitHub source repo 'upstream/master'
#> ✔ Opening '/Users/mine/Desktop/praise/' in new RStudio session
```
</div>

This will create a folder on your Desktop (since we haven't specified an
alternate location for `destdir`) with the same name as the package name, and
forks and clones the package there. It also opens the package in an RStudio
project in a new RStudio session. Note that the protocol used is `ssh` (we can
tell that from the URL of the repo, which starts with `git@` as opposed to `https`).
What this does:

* Forks the praise repo, owned by rladies on GitHub, into your GitHub account.
* Clones your praise repo into a folder named "praise" on your desktop (or
similar).
- `origin` remote is set to your praise repo.
* Does additional git setup:
- `upstream` remote is set to the praise repo owned by rladies.
- `master` branch is set to track `upstream/master`, so you can pull
upstream changes in the future.
* Opens a new instance of RStudio in the praise project, if you're working in
RStudio. Otherwise, switches your current R session to that project.

### Begin contribution
Arguments you might like to know about:

* Specify `fork = TRUE` or `fork = FALSE` if you don't want to defer to the
default behaviour.
* Use `destdir` to put praise in a specific location on your computer.

## Branch, then make your change

We start the process of contributing to the package with `pr_init()`, which
creates a branch in our repository for the pull request, as one should never
submit a pull request from their master branch! We'll call this branch `"yeahyah"`.
creates a branch in our repository for the pull request. It is a good idea to make your pull requests from a non-`master` branch. We'll call this branch `"yeahyah"`.

```{r pr_init, eval=FALSE}
pr_init(branch = "yeahyah")
Expand All @@ -110,12 +117,7 @@ pr_init(branch = "yeahyah")
```
</div>

A local branch called `yeahyah` is created and we switch to this branch.
In RStudio, you will need to hit the refresh button in your Git pane to
observe the that you have indeed been switched over to this branch. Now you can
work locally, making changes to files and checking them into git.

### Submit pull request
This creates a local branch called `yeahyah` and we switch to it (or "check it out"). In RStudio, you may need to hit the refresh button in your Git pane to confirm that you have indeed switched over to this branch. Now you can work locally, making changes to files and commiting that to git.

Let's go ahead and make the change, which is adding the word "yeahyah" to the
`exclamation.R` file in the package. Below is the diff and the commit associated
Expand All @@ -125,11 +127,17 @@ with this change.
knitr::include_graphics("img/pr-functions-diff.png", dpi = 300)
```

You might spot that we made two mistakes here: (1) We intended to add "yeahyah"
but added "yeahyeah" instead, ans (2) we forgot a comma at the end of the line.
You might spot that we made two mistakes here:

1. We intended to add "yeahyah", but added "yeahyeah" instead.
2. We forgot a comma at the end of the line.

Let's assume we didn't actually catch these mistakes, and didn't build and check
the package, which would have revelaed the lack of comma mistake, and initiate
the process for submitting the PR with `pr_push()`.
the package, which would have revealed the missing comma. We all make mistakes.

## Submit pull request

`pr_push()` pushes the local change to your copy of praise on GitHub and puts you in position to make your pull request.

```{r pr_push, eval=FALSE}
pr_push()
Expand All @@ -150,8 +158,7 @@ looks like the following.
knitr::include_graphics("img/pr-functions-pull-request.png", dpi = 300)
```

Once we submit the pull request, GitHub will ping the package maintainer, and they will review our pull request. We can view this pull request in the browser with
`pr_view()`. And anyone can follow along with it [here](https://github.com/rladies/praise/pull/84).
Click "Create pull request" to make the PR. GitHub will ping the package maintainer and they will review our pull request. We can view this pull request in the browser with `pr_view()`. And anyone can follow along with this PR [[rladies/praise#84](https://github.com/rladies/praise/pull/84).

```{r pr_view, eval=FALSE}
pr_view()
Expand All @@ -162,25 +169,21 @@ pr_view()
```
</div>

### Review of the pull request
## Review of the pull request

If we're lucky, and our pull request is perfect, the maintainer will accept it.
However, in this case our it's not perfect. So the package maintainer leaves us
comments requesting changes.
If we're lucky, and our pull request is perfect, the maintainer will accept it, a.k.a. merge it. However, in this case, the PR still needs some work. So the package maintainer leaves us comments requesting changes.

```{r, echo = FALSE}
knitr::include_graphics("img/pr-functions-comments.png", dpi = 300)
```

Being a somewhat careless contributor, we'll address one of these comments (fix
spelling, but still make a mistake!) but not the other (forget to add the comma).
We make the change, and commit it.
Being somewhat new to all this, we try to address one of these comments (fix spelling, but still make a mistake!) and neglect the other (forget to add the comma). We make another change and commit it.

```{r, echo = FALSE}
knitr::include_graphics("img/pr-functions-address-comments.png", dpi = 300)
```

And then run `pr_push()` again to sync back up to GitHub.
Run `pr_push()` again to update the branch in our fork, which is automatically reflected in the PR.

```{r pr_push_again, eval=FALSE}
pr_push()
Expand All @@ -195,10 +198,10 @@ pr_push()
</div>

Now the reviewer gets a chance to review our changes. At this point they might
choose to just make the remaining changes and push their changes into our pull
choose to just make the necessary changes and push their commits into our pull
request to finish things up.

To do so, the reviewer will first fetch the PR with `pr_fetch`.
To do so, the reviewer fetches the PR to their local machine with `pr_fetch()`.

<div class = "reviewer">
```{r pr_fetch_reviewer, eval=FALSE}
Expand All @@ -215,15 +218,13 @@ usethis::pr_fetch(84)
```
</div>

Fetching the PR creates a local branch for them called
`mine-cetinkaya-rundel-yeahyah`, which is a text string comprised of the
Fetching the PR creates a local branch for them called `mine-cetinkaya-rundel-yeahyah`, which is a text string comprised of the
GitHub username of the contributor and the name of the branch they had created
for this PR. `pr_fetch()` also then sets an upstream tracking branch
for the local branch that got created and switches to that branch so the
reviewer can make their changes on the correct branch.

Once the reviewer makes the necessary changes like fixing the spelling (again!)
and adding the missing comma, and then run `pr_push()` to push their changes
Once the reviewer makes the necessary changes, such as fixing the spelling (again!) and adding the missing comma, they run `pr_push()` to push their changes
into our PR.

<div class = "reviewer">
Expand All @@ -239,11 +240,10 @@ usethis::pr_push()
```
</div>

### Wrap up
## Merge and finish

Finally, the reviewer merges our pull request on Github, and then and runs
`pr_finish()` to switch back to the master branch and delete the local branch
created during the process of interacting with our PR.
Finally, the reviewer merges our pull request on GitHub. They can run
`pr_finish()` to switch back to the `master` branch, pull, delete the local branch created during the process of interacting with our PR, and delete the associated remote.

<div class = "reviewer">
```{r pr_finish_reviewer, eval=FALSE}
Expand All @@ -260,7 +260,7 @@ usethis::pr_finish()
</div>

Since the reviewer has contributed some code to our pull request, we can get
that code back to our computer with `pr_pull()`.
that code back to our computer with `pr_pull()`. This is optional here, since the full PR has already been incorporated into `master` of the source repo. But `pr_pull()` can be useful in PRs with if there are a few rounds of alternating contributions from you and the maintainer.

```{r pr_pull, eval=FALSE}
pr_pull()
Expand All @@ -271,8 +271,7 @@ pr_pull()
```
</div>

Finally we can finish the pull request process on our end with `pr_finish()`
as well.
Finally, we can also conclue the PR process on our end with `pr_finish()`.

<div class = "reviewer">
```{r pr_finish_contributor, eval=FALSE}
Expand All @@ -291,24 +290,16 @@ At this point we can use the push button in the RStudio Git pane to push the
last change (deletion of the local `yeahyah` branch) to GitHub so that we
wrap up the PR with everything up-to-date!

Remember you can see how this whole PR unfolded at [rladies/praise#84](https://github.com/rladies/praise/pull/84).

## Other helpful functions

There are a few other functions in the `pr_*` family that we didn't encounter
There are a few other functions in the `pr_*()` family that we didn't encounter
in this PR scenario:

- `pr_pull_upstream()` is used for getting changes that have occured in the
package while we have been working on this PR, i.e. to "merge master".
This makes sure that our copy of the package is up-to-date with the maintainer's
latest changes.

- `pr_sync()` is a a helpful shortcut for pulling changes from the PR
(`pr_pull()`), merging to master (`pr_pull_upstream()`) and pushing all these
changes back into our PR (`pr_push()`). This series of actions might
come in handy when working on an extensive PR that takes some time
to develop while concurrently others are working on the project and making
changes to the master branch.

- `pr_pause()` makes sure you're synced with the PR and then switches back to
the master branch. This is likely something a package maintainer reviewing
numerous PRs will need to use as they switch back and forth from
review to working on master to another review.
package while we have been working on this PR, i.e. to `git pull upstream master`. This makes sure that our copy of the package is up-to-date with the source repo.

- `pr_sync()` is a helpful shortcut for pulling changes from the PR `pr_pull()`), merging to `master` (`pr_pull_upstream()`) and pushing all these changes back into our PR (`pr_push()`). This series of actions might come in handy when working on an extensive PR that takes some time to develop while concurrently others are working on the project and making changes to the `master` branch.

- `pr_pause()` makes sure you're synced with the PR and then switches back to the `master` branch. This is likely something a package maintainer reviewing numerous PRs will need to use as they switch back and forth from review to working on `master` to another review.
4 changes: 2 additions & 2 deletions vignettes/articles/usethis-setup.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ Define any of these options in your `.Rprofile`, which can be opened for editing
```{r, eval = FALSE}
options(
usethis.full_name = "Jane Doe",
usethis.protocol = "ssh",
usethis.description = list(
`Authors@R` = 'person("Jane", "Doe", email = "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "YOUR-ORCID-ID"))',
License = "MIT + file LICENSE",
Version = "0.0.0.9000"
),
usethis.protocol = "ssh"
)
)
```

Expand Down

0 comments on commit 4053147

Please sign in to comment.