|
| 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 | +## Using rspec-dev |
| 10 | + |
| 11 | +See the [rspec-dev README](https://github.com/rspec/rspec-dev#README) |
| 12 | +for setup instructions. |
| 13 | + |
| 14 | +The rspec-dev project contains many rake tasks for helping manage |
| 15 | +an RSpec development environment, making it easy to do things like: |
| 16 | + |
| 17 | +* Change branches across all repos |
| 18 | +* Update all repos with the latest code from `master` |
| 19 | +* Cut a new release across all repos |
| 20 | +* Push out updated build scripts to all repos |
| 21 | + |
| 22 | +These sorts of tasks are essential for the RSpec maintainers but will |
| 23 | +probably be unnecessary complexity if you're just contributing to one |
| 24 | +repository. If you are getting setup to make your first contribution, |
| 25 | +we recommend you take the simpler route of setting up <%= project_name %> |
| 26 | +individually. |
| 27 | + |
| 28 | +## Setting up <%= project_name %> individually |
| 29 | + |
| 30 | +Clone the repo: |
| 31 | + |
| 32 | +``` |
| 33 | +$ git clone [email protected]:rspec/ <%= project_name %>.git |
| 34 | +``` |
| 35 | + |
| 36 | +Install the dependencies using [Bundler](http://bundler.io/): |
| 37 | + |
| 38 | +``` |
| 39 | +$ cd <%= project_name %> |
| 40 | +$ bundle install |
| 41 | +``` |
| 42 | + |
| 43 | +For reasons discussed below, our CI builds avoid loading Bundler at runtime |
| 44 | +by using Bundler's [`--standalone option`](http://myronmars.to/n/dev-blog/2012/03/faster-test-boot-times-with-bundler-standalone). |
| 45 | +While not strictly necessary (many/most of our contributors do not do this!), |
| 46 | +if you want to exactly reproduce our CI builds you'll want to do the same: |
| 47 | + |
| 48 | +``` |
| 49 | +$ bundle install --standalone --binstubs |
| 50 | +``` |
| 51 | + |
| 52 | +The `--binstubs` option creates the `bin/rspec` file that, like `bundle exec rspec`, will load |
| 53 | +all the versions specified in `Gemfile.lock` without loading bundler at runtime! |
| 54 | + |
| 55 | +## Gotcha: Version mismatch from sibling repos |
| 56 | + |
| 57 | +The [../Gemfile] is designed to be flexible and support using |
| 58 | +the other RSpec repositories either from a local sibling directory |
| 59 | +(e.g. `../rspec-<subproject>`) or, if there is no such directory, |
| 60 | +directly from git. This generally does the "right thing", but can |
| 61 | +be a gotcha in some situations. For example, if you are setting up |
| 62 | +`rspec-core`, and you happen to have an old clone of `rspec-expectations` |
| 63 | +in a sibling directory, it'll be used even though it might be months or |
| 64 | +years out of date, which can cause confusing failures. |
| 65 | + |
| 66 | +To avoid this problem, you can either `export USE_GIT_REPOS=1` to force |
| 67 | +the use of `:git` dependencies instead of local dependencies, or update |
| 68 | +the code in the sibling directory. rspec-dev contains rake tasks to |
| 69 | +help you keep all repos in sync. |
| 70 | + |
| 71 | +## Extra Gems |
| 72 | + |
| 73 | +If you need additional gems for any tasks---such as `benchmark-ips` for benchmarking |
| 74 | +or `byebug` for debugging---you can create a `Gemfile-custom` file containing those |
| 75 | +gem declarations. The `Gemfile` evaluates that file if it exists, and it is git-ignored. |
| 76 | + |
| 77 | +# Running the build |
| 78 | + |
| 79 | +The [Travis CI build](https://travis-ci.org/rspec/<%= project_name %>) |
| 80 | +runs many verification steps to prevent regressions and |
| 81 | +ensure high-quality code. To run the Travis build locally, run: |
| 82 | + |
| 83 | +``` |
| 84 | +$ script/run_build |
| 85 | +``` |
| 86 | + |
| 87 | +# What to Expect |
| 88 | + |
| 89 | +To ensure high, uniform code quality, all code changes (including |
| 90 | +changes from the maintainers!) are subject to a pull request code |
| 91 | +review. We'll often ask for clarification or suggest alternate ways |
| 92 | +to do things. Our code reviews are intended to be a two-way |
| 93 | +conversation. |
| 94 | + |
| 95 | +While every user-facing change needs a changelog entry, don't worry |
| 96 | +about adding it yourself. Since the changelog changes to frequently, |
| 97 | +it tends to be the source of merge conflicts when contributors include |
| 98 | +edits in their PRs, so we prefer to add changelog entries ourselves |
| 99 | +after merging your PR. |
| 100 | + |
| 101 | +# Adding Docs |
| 102 | + |
| 103 | +RSpec uses [YARD](http://yardoc.org/) for its API documentation. To |
| 104 | +ensure the docs render well, we recommend running a YARD server and |
| 105 | +viewing your edits in a browser. |
| 106 | + |
| 107 | +To run a YARD server: |
| 108 | + |
| 109 | +``` |
| 110 | +$ bundle exec yard server --reload |
| 111 | + |
| 112 | +# or, if you installed your bundle with `--standalone --binstubs`: |
| 113 | + |
| 114 | +$ bin/yard server --reload |
| 115 | +``` |
| 116 | + |
| 117 | +Then navigate to `localhost:8808` to view the rendered docs. |
| 118 | + |
| 119 | +# The CI build, in detail |
| 120 | + |
| 121 | +As mentioned above, RSpec runs many verification steps as part of its CI build. |
| 122 | +Let's break this down into the individual steps. |
| 123 | + |
| 124 | +## Specs |
| 125 | + |
| 126 | +RSpec dogfoods itself. It's primary defense against regressions is its spec suite. Run with: |
| 127 | + |
| 128 | +``` |
| 129 | +$ bundle exec rspec |
| 130 | + |
| 131 | +# or, if you installed your bundle with `--standalone --binstubs`: |
| 132 | + |
| 133 | +$ bin/rspec |
| 134 | +``` |
| 135 | + |
| 136 | +The spec suite performs a couple extra checks that are worth noting: |
| 137 | + |
| 138 | +* *That all the code is warning-free.* Any individual example that produces output |
| 139 | + to `stderr` will fail. We also have a spec that loads all the `lib` and `spec` |
| 140 | + files in a newly spawned process to detect load-time warnings and fail if there |
| 141 | + are any. RSpec must be warning-free so that users who enable Ruby warnings will |
| 142 | + not get warnings from our code. |
| 143 | +* *That only a minimal set of stdlibs are loaded.* Since Ruby makes loaded libraries |
| 144 | + available for use in any context, we want to minimize how many bits of the standard |
| 145 | + library we load and use. Otherwise, RSpec's use of part of the standard library could |
| 146 | + mask a problem where a gem author forgets to load a part of the standard library they |
| 147 | + rely on. The spec suite contains a spec that defines a whitelist of allowed loaded |
| 148 | + stdlibs. |
| 149 | + |
| 150 | +In addition, we use [SimpleCov](https://github.com/colszowka/simplecov) |
| 151 | +to measure and enforce test coverage. If the coverage falls below a |
| 152 | +project-specific threshold, the build will fail. |
| 153 | + |
| 154 | +## Cukes |
| 155 | + |
| 156 | +RSpec uses [cucumber](https://cucumber.io/) for both acceptance testing and [documentation](https://relishapp.com/rspec). Run with: |
| 157 | + |
| 158 | +``` |
| 159 | +$ bundle exec cucumber |
| 160 | + |
| 161 | +# or, if you installed your bundle with `--standalone --binstubs`: |
| 162 | + |
| 163 | +$ bin/cucumber |
| 164 | +``` |
| 165 | + |
| 166 | +## YARD documentation |
| 167 | + |
| 168 | +RSpec uses [YARD](http://yardoc.org/) for API documentation on the [rspec.info site](http://rspec.info/). |
| 169 | +Our commitment to [SemVer](htp://semver.org) requires that we explicitly |
| 170 | +declare our public API, and our build uses YARD to ensure that every |
| 171 | +class, module and method has either been labeled `@private` or has at |
| 172 | +least some level of documentation. For new APIs, this forces us to make |
| 173 | +an intentional decision about whether or not it should be part of |
| 174 | +RSpec's public API or not. |
| 175 | + |
| 176 | +To run the YARD documentation coverage check, run: |
| 177 | + |
| 178 | +``` |
| 179 | +$ bundle exec yard stats --list-undoc |
| 180 | + |
| 181 | +# or, if you installed your bundle with `--standalone --binstubs`: |
| 182 | + |
| 183 | +$ bin/yard stats --list-undoc |
| 184 | +``` |
| 185 | + |
| 186 | +We also want to prevent YARD errors or warnings when actually generating |
| 187 | +the docs. To check for those, run: |
| 188 | + |
| 189 | +``` |
| 190 | +$ bundle exec yard doc --no-cache |
| 191 | + |
| 192 | +# or, if you installed your bundle with `--standalone --binstubs`: |
| 193 | + |
| 194 | +$ bin/yard doc --no-cache |
| 195 | +``` |
| 196 | + |
| 197 | +## Rubocop |
| 198 | + |
| 199 | +We use [Rubocop](https://github.com/bbatsov/rubocop) to enforce style conventions on the project so |
| 200 | +that the code has stylistic consistency throughout. Run with: |
| 201 | + |
| 202 | +``` |
| 203 | +$ bundle exec rubocop lib |
| 204 | + |
| 205 | +# or, if you installed your bundle with `--standalone --binstubs`: |
| 206 | + |
| 207 | +$ bin/rubocop lib |
| 208 | +``` |
| 209 | + |
| 210 | +Our Rubocop configuration is a work-in-progress, so if you get a failure |
| 211 | +due to a Rubocop default, feel free to ask about changing the |
| 212 | +configuration. Otherwise, you'll need to address the Rubocop failure, |
| 213 | +or, as a measure of last resort, by wrapping the offending code in |
| 214 | +comments like `# rubocop:disable SomeCheck` and `# rubocop:enable SomeCheck`. |
| 215 | + |
| 216 | +## Run spec files one-by-one |
| 217 | + |
| 218 | +A fast TDD cycle depends upon being able to run a single spec file, |
| 219 | +without the rest of the test suite. While rare, it's fairly easy to |
| 220 | +create a situation where a spec passes when the entire suite runs |
| 221 | +but fails when its individual file is run. To guard against this, |
| 222 | +our CI build runs each spec file individually, using a bit of bash like: |
| 223 | + |
| 224 | +``` |
| 225 | +for file in `find spec -iname '*_spec.rb'`; do |
| 226 | + echo "Running $file" |
| 227 | + bin/rspec $file -b --format progress |
| 228 | +done |
| 229 | +``` |
| 230 | + |
| 231 | +Since this step boots RSpec so many times, it runs much, much |
| 232 | +faster when we can avoid the overhead of bundler. This is a main reason our |
| 233 | +CI build installs the bundle with `--standalone --binstubs` and |
| 234 | +runs RSpec via `bin/rspec` rather than `bundle exec rspec`. |
| 235 | + |
| 236 | +## Running the spec suite for each of the other repos |
| 237 | + |
| 238 | +While each of the RSpec repos is an independent gem (generally designed |
| 239 | +to be usable on its own), there are interdependencies between the gems, |
| 240 | +and the specs for each tend to use features from the other gems. We |
| 241 | +don't want to merge a pull request for one repo that might break the |
| 242 | +build for another repo, so our CI build includes a spec that runs the |
| 243 | +spec suite of each of the _other_ project repos. Note that we only run |
| 244 | +the spec suite, not the full build, of the other projects, as the spec |
| 245 | +suite runs very quickly compared to the full build. |
| 246 | + |
0 commit comments