-
-
Notifications
You must be signed in to change notification settings - Fork 28
/
README.Rmd
373 lines (287 loc) · 15.8 KB
/
README.Rmd
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
---
output: github_document
---
# {sandpaper}: User Interface to The Carpentries Workbench <img src='man/figures/logo.png' align='right' alt='' width=120 />
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
eval = FALSE,
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-", out.width = "100%")
```
<!-- badges: start -->
[![R Universe](https://carpentries.r-universe.dev/badges/sandpaper)](https://carpentries.r-universe.dev/ui#builds)
[![Codecov test coverage](https://codecov.io/gh/carpentries/sandpaper/branch/main/graph/badge.svg)](https://codecov.io/gh/carpentries/sandpaper?branch=main)
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental)
[![CRAN status](https://www.r-pkg.org/badges/version/sandpaper)](https://CRAN.R-project.org/package=sandpaper)
[![R-CMD-check](https://github.com/carpentries/sandpaper/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/carpentries/sandpaper/actions/workflows/R-CMD-check.yaml)
<!-- badges: end -->
The {sandpaper} package was created by [The Carpentries] to re-imagine our method
of creating lesson websites for our workshops. This package will take a series
of [Markdown] or [RMarkdown] files and generate a static website with the
features and styling of The Carpentries lessons including customized layouts and
callout blocks. Much of the functionality in this package is inspired by
[Jenny Bryan's](https://jennybryan.org/) work with the [{usethis}] package.
## Documentation
**Want to know how this works in a lesson format? Head over to
<https://carpentries.github.io/sandpaper-docs/>.**
If, instead, you already know how a lesson is built and are interested in
understanding how the functions in {sandpaper} work, you can visit this package
documentation site at <https://carpentries.github.io/sandpaper/>.
## Installation
{sandpaper} is not currently on CRAN, but it can be installed from our
[Carpentries Universe](https://carpentries.r-universe.dev/ui#builds) (updated
every hour) with the following commands:
``` r
options(repos = c(
carpentries = "https://carpentries.r-universe.dev/",
CRAN = "https://cran.rstudio.com/"
))
install.packages("sandpaper", dep = TRUE)
```
Note that this will also install development versions of the following packages:
| package | What it does |
| -------------| ------------ |
| [{varnish}] | html, css, and javascript templates for The Carpentries (in progress) |
| [{tinkr}] | manipulation of knitr markdown documents built on the commonmark xml library |
| [{pegboard}] | programmatic interface to lesson components for validation (in progress) |
## Design
This package is designed to make the life of the lesson contributors and
maintainers easier by separating the tools needed to build the site from the
user-defined content of the site itself. It will no longer rely on Jekyll or
any of the other [>450 static site generators](https://staticsitegenerators.net),
but instead rely on R, RStudio, and [{pkgdown}] to generate a site with the
following features:
- [x] optional offline use
- [x] filename-agnostic episode arrangements
- [x] clear definitions of package versions needed to build the lesson
- [ ] lesson versioning (e.g. I can navigate to
https://swcarpentry.github.io/python-novice-gapminder for the current
version and https://swcarpentry.github.io/python-novice-gapminder/2020-11
for the release in 2020-11)
- [x] seamless updates to the Carpentries' style
- [x] caching of rendered content for rapid deployment
- [ ] packaging of [{learnr}] materials
- [x] validation of lesson structure
- [x] git aware, but does not require contributors to have git installed
### Rendering locally
![The local two-step model of deployment into local folders](vignettes/articles/img/local-flow.dot.svg){alt='diagram of three
folders. The first folder, "episodes/", labelled as RMarkdown, has an arrow
(labelled as hash episodes) pointing to "site/built/", labelled as Markdown.
The Markdown folder has an arrow (labelled as "apply template") pointing to
"site/docs/", labelled as "HTML". The first folder is labelled in pale yellow,
indicating that it is the only one tracked by git.'}
In a repository generated via {sandpaper}, only the source is committed to avoid
issues surrounding out-of-date artefacts and directory structure confusion.
The website is generated in two steps:
1. markdown files from the source files are rendered containing a hash for the
source file so that these need only be re-rendered when they change.
2. html files are generated from the rendered markdown files and the CSS and JS
sources in the [{varnish}] package for the preview.
To ensure there are no clashes between minor differences in the user setup, no
artifacts are committed to the main branch of the repository. Because of the
caching mechanism between the website and the rendered markdown files,
long-running lessons can be updated and previewed quickly.
### Rendering on continuous integration
![Two-step deployment model on continuous integration](vignettes/articles/img/branch-flow.svg){alt='Diagrammatic representation of the GitHub
deployment cycle showing four branches, gh-pages, md-outputs, main, and
my-edit. The my-edit branch is a direct descendent of the main branch, while
the gh-pages and md-outputs branches are orphans. Each commit of the main
branch has a process represented by a dashed arrow that builds a commit of the
subsequent orphan branches'}
Continuous integration will act as the single source-of-truth for how the
outputs of the lessons are rendered. For this, we want the resulting website
to be:
- CI agnostic (but currently set up with GitHub)
- easy to set up
- auditable (e.g. I can see changes between the content of two commits)
- versionable (e.g. I can instruct learners to go to `<WEBSITE>/1.1`. This
is inspired from the python documentation style)
To acheive this, there will be two branches created: `md-outputs` and `gh-pages`
that will inerit like so main -> `md-outputs` -> `gh-pages`. Because the build
time from main to `md-outputs` can be time intensive, this will default to
updating only files that were changed.
- `md-outputs`: this branch will contain the files and artifacts generated from
rmarkdown in the vignettes directory of a thin package skeleton.
- `gh-pages`: this branch is generated via `md-outputs` and bundles the html,
css, and js for the website. This will contain a single `index.html` file
with several subfolders with different versions of the site. The `index.html`
file will redirect to the `current/` directory, which contains the up-to-date
site.
#### Scheduled builds
- `gh-pages` website: Because we are designing the lessons to have content
separated from the styling, we will set up the CI to generate the webpage
from the pre-built sources on a weekly basis, which will check if there has
been an update to the styles (which I have in the [{varnish}] package) and
then rebuild the site without rebuilding the content.
- `md-outputs` branch: This will be rerun every month from scratch with the
most recent version of R and R packages. If there is a change, a pull request
can be generated to update the `renv.lock` file with a link to the changed
markdown files in this branch.
### Function syntax
The functions in {sandpaper} have the following prefixes:
- `create_` will create/amend files or folders in your workspace
- `update_` will update build resources in the lesson
- `build_` will build files from your source
- `validate_` will check the validity of either the elements of the lesson and/or episodes
- `fetch_` will download files or resources from the internet
- `reset_` removes files or information
- `get_` will retrieve information from your source files as an R object
- `set_` will update information in files.
- `ci_` interacts with continous integration to build the website
Here is a working list of user-facing functions:
**Lesson and Episode Creation**
- `create_lesson()` creates a lesson from scratch
- `create_episode()` creates a new episode with the correct number prefix
- `create_dataset()` creates a csv or text data set from an R object
- `set_episodes()` arranges the episodes in a user-specified order
Accessors
- `get_config()` reads the contents of `config.yaml` as a list
- `get_drafts()` reports files that are not listed in `config.yaml`
- `get_episodes()` returns the episode filenames as a vector
- `get_syllabus()` returns the syllabus with timings, titles, and questions
**Website Creation and Validation**
- `validate_lesson()` checks and validates the source files and lesson structure
- `build_episode_md()` renders an individual file to markdown (internal use)
- `build_episode_html()` renders a built markdown file to html (internal use)
- `build_lesson()` builds the lesson into a static website
- `build_portable_lesson()` builds the lesson into a portable static website
**Continuous Integration Utilities**
- `ci_deploy()` builds and deploys the lesson on CI from the source files
- `ci_build_markdown()` builds the markdown files on CI from the source and deploys them to the markdown branch.
- `ci_build_site()` deploys the lesson on CI from pre-rendered markdown files
- `ci_release()` builds and deploys the lesson on CI from the source files and adds a release tag
- `update_github_workflows()` updates GitHub workflows
Cleanup
- `reset_episodes()` removes the schedule from the config.yaml file
- `reset_site()` clears the website and cache
## Usage
There are five use-cases for {sandpaper}:
1. Creating lessons
2. Contributing to lessons
3. Maintaining lessons
4. Rendering a portable site
5. Rendering a site with GitHub actions.
### Creating a lesson
To create a lesson with {sandpaper}, use the `create_lesson()` function:
```{r}
sandpaper::create_lesson("~/Desktop/r-intermediate-penguins")
```
This will create folder on your desktop called `r-intermediate-penguins` with
the following structure:
```
|-- .gitignore # - Ignore everything in the site/ folder
|-- .github/ # - Scripts used for continuous integration
| `-- workflows/ #
| |-- deploy-site.yaml # - Build the source files on github pages
| |-- build-md.yaml # - Build the markdown files on github pages
| `-- cron.yaml # - reset package cache and test
|-- episodes/ # - PUT YOUR MARKDOWN FILES IN THIS FOLDER
| |-- data/ # - Data for your lesson goes here
| |-- figures/ # - All static figures and diagrams are here
| |-- files/ # - Additional files (e.g. handouts)
| `-- 00-introducition.Rmd # - Lessons start with a two-digit number
|-- instructors/ # - Information for Instructors
|-- learners/ # - Information for Learners
| `-- setup.md # - setup instructions (REQUIRED)
|-- profiles/ # - Learner and/or Instructor Profiles
|-- site/ # - This folder is where the rendered markdown files and static site will live
| `-- README.md # - placeholder
|-- config.yaml # - Use this to configure commonly used variables
|-- CONTRIBUTING.md # - Carpentries Rules for Contributions (REQUIRED)
|-- CODE_OF_CONDUCT.md # - Carpentries Code of Conduct (REQUIRED)
|-- LICENSE.md # - Carpentries Licenses (REQUIRED)
`-- README.md # - Introduces folks how to use this lesson and where they can find more information.
```
Once you have your site set up, you can add your RMarkdown files in the episodes
folder. By default, they will be built in alphabetical order, but you can use
the `set_episodes()` command to build the schedule in your `config.yaml` file:
```{r}
s <- sandpaper::get_episodes()
sandpaper::set_episodes(order = s, write = TRUE)
```
When you want to preview your site, use the following:
```{r}
sandpaper::build_lesson()
```
> #### Working in RStudio?
>
> If you are using RStudio, you can preview the lesson site using the keyboard
> shortcut <kbd>ctrl + shift + B</kbd> (which corresponds to the "Build Website" button in the "Build" tab. To preview individual files, you can use
> <kbd>ctrl + shift + K</kbd> (This corresponds to the "Knit" button in the editor pane)
This will create the website structure inside of the the `site/` folder, render
the RMarkdown files to markdown (for inspection and quick rendering), render the
markdown files to HTML, and then enable a preview within your browser window.
### Contributing to a Lesson
To contribute to a lesson, you can either fork the lesson to your own repository
and clone it to your computer manually from GitHub, or you can use the {usethis}
package to automate it. For example, This is how you can create a copy of
[**Programming With R**](http://swcarpentry.github.io/r-novice-inflammation/) to
your computer's Desktop.
```{r}
usethis::create_from_github(
repo = "swcarpentry/r-novice-gapminder",
destdir = "~/Desktop/r-novice-gampinder",
fork = TRUE
)
```
This will copy all of the source files to your computer and move you to the
directory.
### Maintaining a Lesson
When you are maintaining a lesson, there is a high likelihood that you will
already have a copy on your machine. If not, follow the instructions in the
[contributing to a lesson](#contributing-to-a-lesson) section above.
The typical workflow will look like this:
1. open the sandpaper project in RStudio and make edits to files in the
`episodes/` folder
2. in the R console run the following
```{r}
sandpaper::validate_lesson() # validates the structure of the input files
sandpaper::build_lesson() # builds and validates lesson
```
### Rendering a portable site
To render a portable site, you can follow the instructions for [contributing
to a lesson](#contributing-to-a-lesson) or [maintaining a
lesson](#maintaining-a-lesson) to set up. Once you have the lesson set up, you
can use the following command:
```{r}
sandpaper::build_portable_lesson(version = "current")
```
This will render a fully portable lesson site as a zip file in the `site/`
folder. You can distribute this lesson to learners who do not have reliable
internet access for use offline without sacrificing any of the styling.
### Rendering with GitHub actions
Ultimately, there should be a minimal number of functions that handle this
situation because writing CI configuration files is maddening. The most
straightforward function is:
```{r}
sandpaper::ci_deploy(md_branch = "md-outputs", site_branch = "gh-pages")
```
This function will create [git
worktrees](https://git-scm.com/docs/git-worktree) for the orphan `md-outputs`
branch in the `site/built` folder and the orphan `gh-pages` branch in the
`site/docs` folder. After that, we generate the site as normal.
Because css and js libraries may need updating before any lesson material does,
a step can be created just for rebuilding the site that uses:
```{r}
sandpaper::ci_build_site(branch = "gh-pages")
```
When a lesson is given a release, the current site folder needs to be duplicated
to a versioned folder and a tag needs to be added to the `md-outputs` branch:
```{r}
sandpaper::ci_release(tag = "0.1", md_branch = "md-outputs", site_branch = "gh-pages")
```
[The Carpentries]: https://carpentries.org
[Markdown]: https://www.markdownguide.org/getting-started/
[RMarkdown]: https://rmarkdown.rstudio.com/
[{learnr}]: https://rstudio.github.io/learnr/index.html
[{remotes}]: https://remotes.r-lib.org/
[{usethis}]: https://usethis.r-lib.org/
[{gh}]: https://gh.r-lib.org/
[{varnish}]: https://github.com/carpentries/varnish#readme
[{pegboard}]: https://carpentries.github.io/pegboard
[{tinkr}]: https://docs.ropensci.org/tinkr/
[{gert}]: https://github.com/r-lib/gert#readme
[{testthat}]: https://github.com/r-lib/testthat#readme
[{pkgdown}]: https://github.com/r-lib/pkgdown#readme