diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 32e7789..0d52b9d 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -29,3 +29,6 @@ jobs: - name: Run rubocop (complexity checks) run: bundle exec rubocop --parallel + + - name: Run markdownlint + run: bundle exec mdl . diff --git a/.mdl_rules.rb b/.mdl_rules.rb new file mode 100644 index 0000000..b66c5fd --- /dev/null +++ b/.mdl_rules.rb @@ -0,0 +1,2 @@ +all +rule "MD013", ignore_code_blocks: true diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 0000000..9eedc91 --- /dev/null +++ b/.mdlrc @@ -0,0 +1,2 @@ +style File.expand_path("../.mdl_rules.rb", __FILE__) +git_recurse true diff --git a/README.md b/README.md index 924a14c..b5e03de 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,155 @@ # QuietQuality -Work in Progress +There are a lot of different tools that you need to run as you work - possibly +before you commit, or before you make a pull request, or after you make changes +to a class.. style checkers, tests, complexity metrics, static analyzers, etc. +QuietQuality can make that simpler and faster! -But essentially, QuietQuality is intended for two purposes: +Or you may have a huge existing project, that's not _fully_ in compliance with +your style guides, but you want to avoid introducing _new_ issues, without +having to first resolve all of the existing ones. QuietQuality can help with +that too. -1. Let you conveniently run tools like rubocop, rspec, and standard against the _relevant_ - files locally (the files that have changed locally relative to the default branch) -2. Let you run those tools in CI (probably github actions) and annotate any issues found - with _new or modified_ code, without bothering you about existing issues that you didn't - touch. +## Tool Support +So far, we have support for the following tools: -Basic usage examples: +* rubocop +* standardrb +* rspec +* haml-lint +* brakeman (though there's no way to run this against only changed files) +Supporting more tools is relatively straightforward - they're implemented by +wrapping cli invocations and parsing output files (which overall seem to be much +more stable interfaces than the code interfaces to the various tools), and each +tool's support is built orthogonally to the others, in a +`QuietQuality::Tools::[Something]` namespace, with a `Runner` and a `Parser`. + +## Local Usage Examples + +Working locally, you'll generally want to commit a `.quiet_quality.yml` +configuration file into the root of your repository - it'll specify which tools +to run by default, and how to run them (whether you want to only run each tool +against the _changed files_, whether to _filter_ the resulting _messages_ down +to only those targeting lines that have been changed), and allows you to specify +the _comparison branch_, so you don't have to make a request to your origin +server every time you run the tool to see whether you're comparing against +`master` or `main` in this project. + +If you have a configuration set up like that, you might have details specified +for `rubocop`, `rspec`, `standardrb`, and `brakeman`, but have only `rubocop`, +`standardrb`, and `rspec` set to run by default. That configuration file would +look like this (you can copy it from [here](docs/example-config.yml)): + +```yaml +--- +default_tools: ["standardrb", "rubocop", "rspec"] +executor: concurrent +comparison_branch: main +changed_files: true +filter_messages: true +brakeman: + changed_files: false + filter_messages: true ``` -# you have five commits in your feature branch and 3 more files changes but not committed. -# this will run rubocop against all of those files. -qq rubocop - -# run rspec against the changed specs, and annotate any failing specs (well, the first 10 -# of them) against the commit using github's inline output-based annotation approach. Which -# will of course only produce actual annotations if this happens to have been run in a -# github action. -qq rspec --annotate=github_stdout - -# run standardrb against all of the files (not just the changed ones). Still only print out -# problems to lines that have changed, so not particularly useful :-) -qq standard --all --incremental - -# run all of the tools against the entire repository, and print the first three messages -# out for each tool. -qq all --all --full --limit-per-tool=3 + +Then if you invoke `qq`, you'll see output like this: + +```bash +❯ qq +--- Passed: standardrb +--- Passed: rubocop +--- Passed: rspec +``` + +But if you want to run brakeman, you could call `qq brakeman`: + +```bash +❯ qq brakeman +--- Failed: brakeman + + +2 messages: + app/controllers/articles_controller.rb:3 [SQL Injection] Possible SQL injection + app/controllers/articles_controller.rb:11 [Remote Code Execution] `YAML.load` called with parameter value + ``` + +## CI Usage Examples + +Currently, QuietQuality is most useful from GitHub Actions - in that context, it's +possible to generate nice annotations for the analyzed commit (using Workflow +Actions). But it can be used from other CI systems as well, you just won't get +nice annotations out of it (yet). + +For CI systems, you can either configure your execution entirely through +command-line arguments, or you can create additional configuration files and +specify them on the command-line. + +Here is an invocation that executes rubocop and standardrb, expecting the full +repository to pass the latter, but not the former: + +```bash +qq rubocop standardrb \ + --all-files --changed-files rubocop \ + --unfiltered --filter-messages rubocop \ + --comparison-branch main \ + --no-config \ + --executor serial \ + --annotate-github-stdout +``` + +Note the use of `--no-config`, to cause it to _not_ automatically load the +`.quiet_quality.yml` config included in the repository. + +Alternatively, we could have put all of that configuration into a config file +like this: + +```yaml +# config/quiet_quality/linters_workflow.yml +--- +default_tools: ["standardrb", "rubocop"] +executor: serial +comparison_branch: main +changed_files: false +filter_messages: false + +rubocop: + changed_files: true + filter_messages: true +``` + +And then run `qq -C config/quiet_quality/linters_workflow.yml` + +## Available Options + +The configuration file supports the following _global_ options (top-level keys): + +* `executor`: 'serial' or 'concurrent' (the latter is the default) +* `annotator`: none set by default, and `github_stdout` is the only supported + value so far. +* `comparison_branch`: by default, this will be _fetched_ from git, but that + does require a remote request. You should set this, it saves about half a + second. This is normally 'main' or 'master', but it could be 'trunk', or + 'develop' - it is the branch that PR diffs are _against_. +* `changed_files`: defaults to false - should tools be run against only the + files that have changed, or against the entire repository? This is the global + setting, but it is also settable per tool. +* `filter_messages`: defaults to false - should the resulting messages that do + not refer to lines that were changed or added relative to the comparison + branch be skipped? Also possible to set for each tool. + +And then each tool can have an entry, within which `changed_files` and +`filter_messages` can be specified - the tool-specific settings override the +global ones. + +### CLI Options + +The same options are all available on the CLI, plus some additional ones - run +`qq --help` for a detailed list of the options, but the notable additions are: + +* `--help/-H`: See a list of the options +* `--no-config/-N`: Do _not_ load a config file, even if present. +* `--config/-C` load the supplied config file (instead of the detected one, if + found) diff --git a/docs/example-config.yml b/docs/example-config.yml new file mode 100644 index 0000000..1041227 --- /dev/null +++ b/docs/example-config.yml @@ -0,0 +1,9 @@ +--- +default_tools: ["standardrb", "rubocop", "rspec"] +executor: concurrent +comparison_branch: main +changed_files: true +filter_messages: true +brakeman: + changed_files: false + filter_messages: true diff --git a/quiet_quality.gemspec b/quiet_quality.gemspec index 0485b15..941d119 100644 --- a/quiet_quality.gemspec +++ b/quiet_quality.gemspec @@ -41,4 +41,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "standard", "~> 1.28" spec.add_development_dependency "rubocop", "~> 1.50" spec.add_development_dependency "debug" + spec.add_development_dependency "mdl", "~> 0.12" end