Shared linter configs and thin wrappers.
Baseline is responsible for canonical configuration only. Consuming repositories are responsible for installing runtimes and linter binaries before running baseline hooks or actions.
Replace VERSION in all examples with the latest release tag from
github.com/rubykatzen/baseline/releases.
After initial setup, Dependabot keeps the pin current automatically.
Create .github/workflows/lint.yml. Include only the linters relevant to your stack:
name: Lint
on:
push:
branches: ["main"]
pull_request:
jobs:
lint:
uses: rubykatzen/baseline/.github/workflows/lint-shared.yml@VERSION
with:
linters: yamllint, pymarkdown, ruff, shellcheck, actionlint, rubocop, erb-lint, herb, pre-commitlint-shared.yml installs runtimes and runs each linter automatically. Add
pre-commit to linters to enforce that .pre-commit-config.yaml hooks stay
in sync with CI.
Copy .pre-commit-config.yaml.example to your repo or add to your existing config.
Include only the hooks relevant to your stack:
repos:
- repo: https://github.com/rubykatzen/baseline
rev: v0.7.8
hooks:
- id: yamllint
- id: pymarkdown
- id: ruff
- id: shellcheck
- id: actionlint
- id: rubocop
- id: erb-lintRemove hooks you don't need. Install the tools before running hooks:
python -m pip install yamllint pymarkdownlnt ruff
brew install shellcheck actionlintRuby hooks use bundle exec; install Ruby and run bundle install in the
consuming repository first. rubocop and erb_lint must be available through
the rubykatzen-baseline gem.
Add .github/dependabot.yml to keep GitHub Actions and pre-commit pins
current automatically:
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
time: "10:00"
timezone: "Europe/Berlin"
- package-ecosystem: pre-commit
directory: /
schedule:
interval: daily
time: "10:00"
timezone: "Europe/Berlin"Dependabot opens pull requests for version bumps. Pair with
dependabot-automerge if you want patch/minor updates merged automatically.
Pass these keys to lint-shared.yml via linters::
| Key | Action | Lints | Config |
|---|---|---|---|
yamllint |
lint-yamllint |
*.yml, *.yaml |
config/yamllint.yml |
pymarkdown |
lint-pymarkdown |
*.md |
config/pymarkdown.json |
ruff |
lint-ruff |
*.py |
config/ruff.toml |
shellcheck |
lint-shellcheck |
*.sh |
config/shellcheck.rc |
actionlint |
lint-actionlint |
.github/workflows/*.yml |
— |
rubocop |
lint-rubocop |
*.rb |
config/rubocop.yml |
erb-lint |
lint-erb-lint |
*.erb |
config/erb_lint.yml |
herb |
lint-herb |
*.html.erb, *.html+*.erb, *.turbo_stream.erb, *.herb, *.rhtml |
— |
pre-commit |
check-precommit-sync |
.pre-commit-config.yaml |
— |
check-precommit-sync runs two checks:
- Coverage — scans repo files and verifies that every baseline hook whose file type is present is configured in
.pre-commit-config.yaml - Sync — verifies that configured hooks match the
lintersinput (minuspre-commititself)
For Rails and other Ruby projects, install the shared configs through the rubykatzen-baseline
gem instead of listing RuboCop gems separately. Configs still live in this
repository and ship inside the gem — consumer repos only add stub files that
inherit from the gem.
Replace individual RuboCop gems with a single baseline pin:
group :development, :test do
gem "rubykatzen-baseline", require: false
endThe gem pulls in rubocop, rubocop-performance, rubocop-rails,
standard-custom, and erb_lint as dependencies.
Run once from the project root after bundle install:
bundle exec baseline-installThis creates stub configs when missing:
# .rubocop.yml
inherit_gem:
rubykatzen-baseline: config/rubocop.yml
# Generate project-specific excludes, then uncomment inherit_from below:
# bundle exec rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 10000
# inherit_from:
# - .rubocop_todo.yml# .erb_lint.yml
inherit_gem:
rubykatzen-baseline: config/erb_lint.yml
# Generate .erb_lint_todo.yml, then uncomment inherit_from below:
# bundle exec erb_lint --enable-all-linters --lint-all
# inherit_from:
# - .erb_lint_todo.ymlStubs work out of the box with shared baseline cops only. Uncomment
inherit_from after creating todo files for project-specific excludes.
erb_lint has no --auto-gen-config. To suppress existing violations while
keeping new ones visible, create .erb_lint_todo.yml manually:
-
Run erb_lint and collect the cop names that appear:
bundle exec erb_lint --lint-all -
Create
.erb_lint_todo.ymlin the project root. Use the erb_lint config format — cop names go insidelinters.Rubocop.rubocop_config, not at the top level:# .erb_lint_todo.yml # Remove cops from this list as you fix templates. linters: Rubocop: rubocop_config: Layout/ArgumentAlignment: Enabled: false Style/FrozenStringLiteralComment: Enabled: false
-
Uncomment
inherit_fromin.erb_lint.yml:inherit_gem: rubykatzen-baseline: config/erb_lint.yml inherit_from: - .erb_lint_todo.yml
Remove cops from the todo file as you fix the templates.
bundle exec rubocop
bundle exec rubocop -A
bundle exec erb_lint --lint-allThe rubocop and erb-lint pre-commit hooks and GitHub Actions require the
baseline gem in the project Gemfile plus the generated stubs above. They
delegate to the same bundle exec commands so local and CI linting use one
Bundler-resolved toolchain.
Baseline releases are cut with the rubykatzen/releaser CLI. Run from inside this repository:
releaser patch # or: releaser minor / releaser majorThe CLI verifies that CI is green on origin/main, calculates the next version,
dispatches prepare-release.yml, watches it run, then opens a release/vX.Y.Z
PR and enables auto-merge. publish-release.yml fires automatically once the PR
merges and creates the tag and GitHub release.
Check release readiness without triggering anything:
releaser status
releaser patch --dry-runInstall the CLI:
brew tap rubykatzen/tap && brew install releaserSee LINTERS-DEFAULTS-OVERRIDES.md for a full list of deviations from each linter's defaults with rationale.