Skip to content

Commit 74c03e2

Browse files
committed
Merge pull request #127 from rspec/add-contributing-docs
Contributing doc
2 parents 8510d5f + cb49699 commit 74c03e2

File tree

4 files changed

+311
-4
lines changed

4 files changed

+311
-4
lines changed

Rakefile

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ require 'pathname'
44
require 'bundler'
55
require 'time'
66
require 'date'
7+
require 'erb'
78

89
Projects = ['rspec', 'rspec-core', 'rspec-expectations', 'rspec-mocks', 'rspec-rails', 'rspec-support']
910
UnDocumentedProjects = %w[ rspec rspec-support ]
@@ -287,23 +288,25 @@ end
287288
namespace :common_markdown_files do
288289
def update_common_markdown_files_in_repos
289290
update_files_in_repos('common markdown files', ' [ci skip]') do |name|
290-
common_markdown_files_with_comments.each do |file|
291+
common_markdown_files_with_comments(name).each do |file|
291292
full_file_name = ReposPath.join(name, file.file_name)
292293
full_file_name.write(file.contents)
293294
full_file_name.chmod(file.mode) # ensure executables are set
294295
end
295296
end
296297
end
297298

298-
def common_markdown_files_with_comments
299+
def common_markdown_files_with_comments(project_name)
299300
markdown_root = BaseRspecPath.join('common_markdown_files')
300301
file_names = Pathname.glob(markdown_root.join('**', '{*,.*}')).select do |f|
301302
f.file?
302303
end
303304

304305
file_names.map do |file|
305306
comments_added = false
306-
lines = file.each_line.each_with_object([]) do |line, all|
307+
content = markdown_file_content(file, project_name)
308+
309+
lines = content.each_line.each_with_object([]) do |line, all|
307310
if !comments_added && !line.start_with?('#!')
308311
all.concat([
309312
"<!---\n",
@@ -318,13 +321,26 @@ namespace :common_markdown_files do
318321
end
319322

320323
ReadFile.new(
321-
file.relative_path_from(markdown_root),
324+
file.relative_path_from(markdown_root).sub(/\.erb$/, ''),
322325
lines.join,
323326
file.stat.mode
324327
)
325328
end
326329
end
327330

331+
ERBRenderer = Struct.new(:project_name, :contents) do
332+
def render
333+
# Our `binding` makes `project_name` available to the ERB template.
334+
ERB.new(contents).result(binding)
335+
end
336+
end
337+
338+
def markdown_file_content(file, project_name)
339+
raw_contents = file.read
340+
return raw_contents unless file.extname == ".erb"
341+
ERBRenderer.new(project_name, raw_contents).render
342+
end
343+
328344
desc "Update common markdown files"
329345
task :update_files do
330346
update_common_markdown_files_in_repos
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# The CI build, in detail
2+
3+
The [Travis CI build](https://travis-ci.org/rspec/<%= project_name %>)
4+
runs many verification steps to prevent regressions and
5+
ensure high-quality code. To run the Travis build locally, run:
6+
7+
```
8+
$ script/run_build
9+
```
10+
11+
It can be useful to run the build steps individually
12+
to repro a failing part of a Travis build. Let's break
13+
the build down into the individual steps.
14+
15+
## Specs
16+
17+
RSpec dogfoods itself. Its primary defense against regressions is its spec suite. Run with:
18+
19+
```
20+
$ bundle exec rspec
21+
22+
# or, if you installed your bundle with `--standalone --binstubs`:
23+
24+
$ bin/rspec
25+
```
26+
27+
The spec suite performs a couple extra checks that are worth noting:
28+
29+
* *That all the code is warning-free.* Any individual example that produces output
30+
to `stderr` will fail. We also have a spec that loads all the `lib` and `spec`
31+
files in a newly spawned process to detect load-time warnings and fail if there
32+
are any. RSpec must be warning-free so that users who enable Ruby warnings will
33+
not get warnings from our code.
34+
* *That only a minimal set of stdlibs are loaded.* Since Ruby makes loaded libraries
35+
available for use in any context, we want to minimize how many bits of the standard
36+
library we load and use. Otherwise, RSpec's use of part of the standard library could
37+
mask a problem where a gem author forgets to load a part of the standard library they
38+
rely on. The spec suite contains a spec that defines a whitelist of allowed loaded
39+
stdlibs.
40+
41+
In addition, we use [SimpleCov](https://github.com/colszowka/simplecov)
42+
to measure and enforce test coverage. If the coverage falls below a
43+
project-specific threshold, the build will fail.
44+
45+
## Cukes
46+
47+
RSpec uses [cucumber](https://cucumber.io/) for both acceptance testing
48+
and [documentation](https://relishapp.com/rspec). Since we publish our cukes
49+
as documentation, please limit new cucumber scenarios to user-facing examples
50+
that help demonstrate usage. Any tests that exist purely to prevent regressions
51+
should be written as specs, even if they are written in an acceptance style.
52+
Duplication between our YARD API docs and the cucumber documentation is fine.
53+
54+
Run with:
55+
56+
```
57+
$ bundle exec cucumber
58+
59+
# or, if you installed your bundle with `--standalone --binstubs`:
60+
61+
$ bin/cucumber
62+
```
63+
64+
## YARD documentation
65+
66+
RSpec uses [YARD](http://yardoc.org/) for API documentation on the [rspec.info site](http://rspec.info/).
67+
Our commitment to [SemVer](htp://semver.org) requires that we explicitly
68+
declare our public API, and our build uses YARD to ensure that every
69+
class, module and method has either been labeled `@private` or has at
70+
least some level of documentation. For new APIs, this forces us to make
71+
an intentional decision about whether or not it should be part of
72+
RSpec's public API or not.
73+
74+
To run the YARD documentation coverage check, run:
75+
76+
```
77+
$ bundle exec yard stats --list-undoc
78+
79+
# or, if you installed your bundle with `--standalone --binstubs`:
80+
81+
$ bin/yard stats --list-undoc
82+
```
83+
84+
We also want to prevent YARD errors or warnings when actually generating
85+
the docs. To check for those, run:
86+
87+
```
88+
$ bundle exec yard doc --no-cache
89+
90+
# or, if you installed your bundle with `--standalone --binstubs`:
91+
92+
$ bin/yard doc --no-cache
93+
```
94+
95+
## Rubocop
96+
97+
We use [Rubocop](https://github.com/bbatsov/rubocop) to enforce style conventions on the project so
98+
that the code has stylistic consistency throughout. Run with:
99+
100+
```
101+
$ bundle exec rubocop lib
102+
103+
# or, if you installed your bundle with `--standalone --binstubs`:
104+
105+
$ bin/rubocop lib
106+
```
107+
108+
Our Rubocop configuration is a work-in-progress, so if you get a failure
109+
due to a Rubocop default, feel free to ask about changing the
110+
configuration. Otherwise, you'll need to address the Rubocop failure,
111+
or, as a measure of last resort, by wrapping the offending code in
112+
comments like `# rubocop:disable SomeCheck` and `# rubocop:enable SomeCheck`.
113+
114+
## Run spec files one-by-one
115+
116+
A fast TDD cycle depends upon being able to run a single spec file,
117+
without the rest of the test suite. While rare, it's fairly easy to
118+
create a situation where a spec passes when the entire suite runs
119+
but fails when its individual file is run. To guard against this,
120+
our CI build runs each spec file individually, using a bit of bash like:
121+
122+
```
123+
for file in `find spec -iname '*_spec.rb'`; do
124+
echo "Running $file"
125+
bin/rspec $file -b --format progress
126+
done
127+
```
128+
129+
Since this step boots RSpec so many times, it runs much, much
130+
faster when we can avoid the overhead of bundler. This is a main reason our
131+
CI build installs the bundle with `--standalone --binstubs` and
132+
runs RSpec via `bin/rspec` rather than `bundle exec rspec`.
133+
134+
## Running the spec suite for each of the other repos
135+
136+
While each of the RSpec repos is an independent gem (generally designed
137+
to be usable on its own), there are interdependencies between the gems,
138+
and the specs for each tend to use features from the other gems. We
139+
don't want to merge a pull request for one repo that might break the
140+
build for another repo, so our CI build includes a spec that runs the
141+
spec suite of each of the _other_ project repos. Note that we only run
142+
the spec suite, not the full build, of the other projects, as the spec
143+
suite runs very quickly compared to the full build.
144+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Contributing
2+
3+
RSpec is a community-driven project that has benefited from improvements from over over *500* contributors.
4+
We welcome contributions from *everyone*. While contributing, please follow the project [code of conduct](code_of_conduct.md), so that everyone can be included.
5+
6+
If you'd like to help make RSpec better, here are some ways you can contribute:
7+
8+
- by running RSpec HEAD to help us catch bugs before new releases
9+
- by [reporting bugs you encounter](https://github.com/rspec/<%= project_name %>/issues/new)
10+
- by [suggesting new features](https://github.com/rspec/<%= project_name %>/issues/new)
11+
- by improving RSpec's [Relish](https://relishapp.com/rspec) or [API](http://rspec.info/documentation/) documentation
12+
- by improving [RSpec's website](http://rspec.info/) ([source](https://github.com/rspec/rspec.github.io))
13+
- by taking part in [feature and issue discussions](https://github.com/rspec/<%= project_name %>/issues)
14+
- by adding a failing test for reproducible [reported bugs](https://github.com/rspec/<%= project_name %>/issues)
15+
- by reviewing [pull requests](https://github.com/rspec/<%= project_name %>/pulls) and suggesting improvements
16+
- by [writing code](DEVELOPMENT.md) (no patch is too small! fix typos or bad whitespace)
17+
18+
If you need help getting started, check out the [DEVELOPMENT](DEVELOPMENT.md) file for steps that will get you up and running.
19+
20+
Thanks for helping us make RSpec better!
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Development Setup
2+
3+
Generally speaking, you only need to clone the project and install
4+
the dependencies with [Bundler](http://bundler.io/). You can either
5+
get a full RSpec development environment using
6+
[rspec-dev](https://github.com/rspec/rspec-dev#README) or you can
7+
set this project up individually.
8+
9+
## Setting up <%= project_name %> individually
10+
11+
For most contributors, setting up the project individually will be simpler.
12+
Unless you have a specific reason to use rspec-dev, we recommend using this approach.
13+
14+
Clone the repo:
15+
16+
```
17+
$ git clone [email protected]:rspec/<%= project_name %>.git
18+
```
19+
20+
Install the dependencies using [Bundler](http://bundler.io/):
21+
22+
```
23+
$ cd <%= project_name %>
24+
$ bundle install
25+
```
26+
27+
To minimize boot time and to ensure we don't depend upon any extra dependencies
28+
loaded by Bundler, our CI builds avoid loading Bundler at runtime
29+
by using Bundler's [`--standalone option`](http://myronmars.to/n/dev-blog/2012/03/faster-test-boot-times-with-bundler-standalone).
30+
While not strictly necessary (many/most of our contributors do not do this!),
31+
if you want to exactly reproduce our CI builds you'll want to do the same:
32+
33+
```
34+
$ bundle install --standalone --binstubs
35+
```
36+
37+
The `--binstubs` option creates the `bin/rspec` file that, like `bundle exec rspec`, will load
38+
all the versions specified in `Gemfile.lock` without loading bundler at runtime!
39+
40+
## Using rspec-dev
41+
42+
See the [rspec-dev README](https://github.com/rspec/rspec-dev#README)
43+
for setup instructions.
44+
45+
The rspec-dev project contains many rake tasks for helping manage
46+
an RSpec development environment, making it easy to do things like:
47+
48+
* Change branches across all repos
49+
* Update all repos with the latest code from `master`
50+
* Cut a new release across all repos
51+
* Push out updated build scripts to all repos
52+
53+
These sorts of tasks are essential for the RSpec maintainers but will
54+
probably be unnecessary complexity if you're just contributing to one
55+
repository. If you are getting setup to make your first contribution,
56+
we recommend you take the simpler route of setting up <%= project_name %>
57+
individually.
58+
59+
## Gotcha: Version mismatch from sibling repos
60+
61+
The [Gemfile](Gemfile) is designed to be flexible and support using
62+
the other RSpec repositories either from a local sibling directory
63+
(e.g. `../rspec-<subproject>`) or, if there is no such directory,
64+
directly from git. This generally does the "right thing", but can
65+
be a gotcha in some situations. For example, if you are setting up
66+
`rspec-core`, and you happen to have an old clone of `rspec-expectations`
67+
in a sibling directory, it'll be used even though it might be months or
68+
years out of date, which can cause confusing failures.
69+
70+
To avoid this problem, you can either `export USE_GIT_REPOS=1` to force
71+
the use of `:git` dependencies instead of local dependencies, or update
72+
the code in the sibling directory. rspec-dev contains rake tasks to
73+
help you keep all repos in sync.
74+
75+
## Extra Gems
76+
77+
If you need additional gems for any tasks---such as `benchmark-ips` for benchmarking
78+
or `byebug` for debugging---you can create a `Gemfile-custom` file containing those
79+
gem declarations. The `Gemfile` evaluates that file if it exists, and it is git-ignored.
80+
81+
# Running the build
82+
83+
The [Travis CI build](https://travis-ci.org/rspec/<%= project_name %>)
84+
runs many verification steps to prevent regressions and
85+
ensure high-quality code. To run the Travis build locally, run:
86+
87+
```
88+
$ script/run_build
89+
```
90+
91+
See [build detail](BUILD_DETAIL.md) for more detail.
92+
93+
# What to Expect
94+
95+
To ensure high, uniform code quality, all code changes (including
96+
changes from the maintainers!) are subject to a pull request code
97+
review. We'll often ask for clarification or suggest alternate ways
98+
to do things. Our code reviews are intended to be a two-way
99+
conversation.
100+
101+
Here's a short, non-exhaustive checklist of things we typically ask contributors to do before PRs are ready to merge. It can help get your PR merged faster if you do these in advance!
102+
103+
- [ ] New behavior is covered by tests and all tests are passing.
104+
- [ ] No Ruby warnings are issued by your changes.
105+
- [ ] Documentation reflects changes and renders as intended.
106+
- [ ] Rubocop passes (e.g. `bundle exec rubocop lib`).
107+
- [ ] Commits are squashed into a reasonable number of logical changesets that tell an easy-to-follow story.
108+
- [ ] No changelog entry is necessary (we'll add it as part of the merge process!)
109+
110+
# Adding Docs
111+
112+
RSpec uses [YARD](http://yardoc.org/) for its API documentation. To
113+
ensure the docs render well, we recommend running a YARD server and
114+
viewing your edits in a browser.
115+
116+
To run a YARD server:
117+
118+
```
119+
$ bundle exec yard server --reload
120+
121+
# or, if you installed your bundle with `--standalone --binstubs`:
122+
123+
$ bin/yard server --reload
124+
```
125+
126+
Then navigate to `localhost:8808` to view the rendered docs.
127+

0 commit comments

Comments
 (0)