Before creating a new branch, always sync and clean up:
git checkout master
git pull upstream master
git branch --merged master | grep -v '^\* \|^ master$' | xargs -r git branch -d
Always run before committing:
bundle exec rake
This runs RuboCop and the full RSpec suite. If RuboCop reports offenses, fix them with bundle exec rubocop -a then re-run.
For code you write, fix RuboCop offenses directly rather than adding them to .rubocop_todo.yml. If a fix is non-trivial, it is acceptable to run bundle exec rubocop --auto-gen-config to update the todo file instead.
- Tests live in
spec/grape/and use RSpec. - Add tests for all new features and bug fixes in the appropriate
spec/grape/subdirectory. - Run a single spec file with
bundle exec rspec spec/path/to/file_spec.rb. - Run the full RSpec suite with
bundle exec rspec. - The test suite uses
rack-testfor HTTP-level specs. IncludeRack::Test::Methodsand defineappin specs that need it.
Update CHANGELOG.md for every user-facing change. Add a line under #### Features or #### Fixes in the current unreleased section at the top, in this format:
* [#PR](https://github.com/ruby-grape/grape/pull/PR): Description of change - [@username](https://github.com/username).
Keep the entry to a single short line — one clause naming the change at a high level. Detail belongs in the PR description, not the changelog. Open the PR with no changelog entry first (or with a placeholder), then amend the commit with the real entry once the PR number is assigned. The "Your contribution here." line must remain last in each section.
Update UPGRADING.md only when introducing a contract break — a change in documented behavior or public API that an upgrading user has to act on. Pure refactors, internal cleanups, performance work, and additive options do not need an UPGRADING entry. Add a subsection under the current version heading (e.g. ### Upgrading to >= 3.2.0), describing what changed and how to adapt.
- Ruby style is enforced via RuboCop (
.rubocop.yml), with pinned gem versions inGemfile. - Run
bundle exec rubocopto check andbundle exec rubocop -ato auto-fix. - Frozen string literals are required in all files (
# frozen_string_literal: true). - Minimum Ruby version is 3.2.
Beyond what RuboCop enforces, prefer:
- Guard clauses over trailing
if/else(and overif/elsif/elsif/elseladders). When a method ends in branching where one or more arms is a short special case, lift each special case to areturn … if …/return … unless …so the main flow sits at top indentation. Reach for guards even when none of the branches are obviously "the special case" — three guards followed by a bare expression is usually clearer than a three-armif/elsif/else. - Don't return from inside a
case/when. If awhenbranch should short-circuit the method, lift it to a guard clause above thecase; thewhenarms then stay as plain expressions evaluating to a value. - Don't use
case/whenfor class-identity dispatch.when SomeClassmatches with===, i.e.value.is_a?(SomeClass)— that's correct only when dispatching on an instance. When dispatching on a class value (e.g.typeis the class itself), useif type == Xor[X, Y].include?(type)instead. - No comments restating what the code does. Reserve comments for why something non-obvious is happening (hidden constraint, surprising invariant, workaround) — well-named identifiers carry the what.
- Never push directly to master — always work on a branch and open a PR targeting
ruby-grape/grape master. - One commit per PR, kept current by amending — don't stack follow-up "address review" or "fix CI" commits on the branch. After amending, force-push with
git push --force-with-lease(never plain--force). - Split changes by concern: one logical refactor / feature / fix per PR. When a working tree contains unrelated changes, stash the others and open them separately rather than bundling.
- PR titles and commit messages should be clear and imperative (e.g. "Fix UnknownAuthStrategy when subclassing Auth::Base").
- Reference the related issue in the commit message and PR description (e.g.
Fixes #1234).
When origin/master advances and an open branch needs to catch up:
git fetch origin master
git checkout <branch>
git rebase origin/master
# resolve conflicts, run the touched specs
git push --force-with-lease origin <branch>
CHANGELOG conflicts are common when two open PRs both add entries at the bottom of #### Features / #### Fixes — resolve by keeping both entries in PR-number order (oldest first). Mixed conflicts in lib/ should be resolved on their merits: preserve the master version's structural changes and re-apply the branch's intent on top, rather than reverting either side wholesale.
Core runtime dependencies are declared in grape.gemspec. Development and test dependencies are in Gemfile. Do not add new runtime dependencies without discussion; prefer what is already available (ActiveSupport, dry-types, Rack).
The gemfiles/ directory contains alternate Gemfiles for testing against different Rack and Rails versions. CI runs against all of them. When fixing compatibility issues, test locally with:
BUNDLE_GEMFILE=gemfiles/rack_3_2.gemfile bundle exec rspec