rails_git_hooks 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -2
- data/README.md +149 -83
- data/lib/rails_git_hooks/checks/base.rb +55 -0
- data/lib/rails_git_hooks/checks/commit_msg/jira_prefix.rb +31 -0
- data/lib/rails_git_hooks/checks/commit_msg.rb +10 -0
- data/lib/rails_git_hooks/checks/pre_commit/debugger_check.rb +43 -0
- data/lib/rails_git_hooks/checks/pre_commit/default_branch.rb +20 -0
- data/lib/rails_git_hooks/checks/pre_commit/json_format_check.rb +30 -0
- data/lib/rails_git_hooks/checks/pre_commit/migrations_check.rb +37 -0
- data/lib/rails_git_hooks/checks/pre_commit/rubocop.rb +30 -0
- data/lib/rails_git_hooks/checks/pre_commit/whitespace_check.rb +31 -0
- data/lib/rails_git_hooks/checks/pre_commit/yaml_format_check.rb +31 -0
- data/lib/rails_git_hooks/checks/pre_commit.rb +16 -0
- data/lib/rails_git_hooks/checks/pre_push/run_tests.rb +24 -0
- data/lib/rails_git_hooks/checks/pre_push.rb +10 -0
- data/lib/rails_git_hooks/checks.rb +6 -0
- data/lib/rails_git_hooks/cli.rb +85 -64
- data/lib/rails_git_hooks/config/constants.rb +20 -0
- data/lib/rails_git_hooks/config/defaults.yml +127 -0
- data/lib/rails_git_hooks/config/defaults_loader.rb +42 -0
- data/lib/rails_git_hooks/core/check_definition.rb +63 -0
- data/lib/rails_git_hooks/core/check_result.rb +41 -0
- data/lib/rails_git_hooks/core/error.rb +5 -0
- data/lib/rails_git_hooks/install/installer.rb +53 -0
- data/lib/rails_git_hooks/runtime/check_registry.rb +29 -0
- data/lib/rails_git_hooks/runtime/dependency_checker.rb +51 -0
- data/lib/rails_git_hooks/runtime/file_matcher.rb +23 -0
- data/lib/rails_git_hooks/runtime/override_config.rb +125 -0
- data/lib/rails_git_hooks/runtime/policy_resolver.rb +36 -0
- data/lib/rails_git_hooks/runtime/repository.rb +61 -0
- data/lib/rails_git_hooks/runtime/runner.rb +76 -0
- data/lib/rails_git_hooks/runtime.rb +25 -0
- data/lib/rails_git_hooks/version.rb +1 -1
- data/lib/rails_git_hooks.rb +14 -5
- data/templates/hooks/commit-msg +13 -0
- data/templates/hooks/pre-commit +13 -0
- data/templates/hooks/pre-push +13 -0
- metadata +33 -5
- data/lib/rails_git_hooks/installer.rb +0 -118
- data/lib/rails_git_hooks/templates/commit-msg +0 -32
- data/lib/rails_git_hooks/templates/pre-commit +0 -58
- data/lib/rails_git_hooks/templates/pre-push +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b95455f85a5e5f3789055e84fc610dcfa199f593d3fc34e5dfb94b781b0ad050
|
|
4
|
+
data.tar.gz: d2f37971fb832ba3c0e2b3651c7d27b4ca8a7665d6fdac879a43eac8ca38b022
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93b5d01ffd6b14ed1d94543a41e95286afbcaa1f808d9c1d4045dd193e9de3a9f02b3b8a5d5374eadaea450028b28ee89a09c1af20869e30cd8cdeeb8620f259
|
|
7
|
+
data.tar.gz: 549b45c9aeb5f9607c5aa779d4fdf71196d7d08525f79cfde5e3bf2c3a7df107aa34e397258d4218e45a026e6ed474ab6bb4fc906174af0876eb61ba5cd4e44b
|
data/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,39 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
|
|
7
|
-
## [0.
|
|
7
|
+
## [0.7.1]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Code-first runtime architecture** — Hook behavior now lives in Ruby classes with a central runner, registry, policy resolver, dependency checker, and sparse override config loader.
|
|
12
|
+
- **Sparse override config** — Added optional `.rails_git_hooks.yml` with Overcommit-style per-check overrides for `enabled`, `quiet`, `on_fail`, `on_warn`, `on_missing_dependency`, `include`, `exclude`, and `command`.
|
|
13
|
+
- **Thin hook bootstraps** — `templates/hooks/*` now dispatch into the embedded `rails_git_hooks` runtime instead of loading copied script files per check.
|
|
14
|
+
- **Pre-commit YAML format check** — Warns (does not block) when any staged `.yml` or `.yaml` file fails to parse (invalid YAML). Reports file and line from the parser. On by default with pre-commit.
|
|
15
|
+
- **Pre-commit JSON format check** — Warns (does not block) when any staged `.json` file fails to parse (invalid JSON). Reports file and parser message. On by default with pre-commit.
|
|
16
|
+
- **Pre-commit migrations check** — Warns (does not block) when: (a) migration file(s) are staged but neither `db/schema.rb` nor `db/structure.sql` is staged; (b) data migration file(s) in `db/data/` or `db/data_migrate/` are staged but `db/data_schema.rb` is not. **On by default.** Disable with `rails_git_hooks disable migrations-check`.
|
|
17
|
+
- **Defaults YAML** — `lib/rails_git_hooks/config/defaults.yml` holds default settings for every check and hook. `DefaultsLoader` reads it; `OverrideConfig` uses it as the base when merging with `.rails_git_hooks.yml`. Edit the YAML to change built-in defaults.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **CLI redesign** — Replaced per-check flag-file commands with generic config-driven commands: `install`, `list`, `init`, `enable`, `disable`, `set`, and `show-config`.
|
|
22
|
+
- **Manual install layout** — Manual install is via `bundle exec rails_git_hooks install` only; dropped `rake sync_hooks` and the repo `hooks/` tree.
|
|
23
|
+
- **Dependency handling** — Checks can now declare executables, Ruby libraries, files, and install hints, with centralized `on_missing_dependency` policy handling.
|
|
24
|
+
- **Runtime install** — Installer copies all runtime files (including `config/defaults.yml`), not only `*.rb`, into `.git/hooks/rails_git_hooks/`.
|
|
25
|
+
- **Removed `hooks/` directory** — `/hooks/` added to `.gitignore`. README manual-install section updated.
|
|
26
|
+
|
|
27
|
+
## [0.7.0]
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Overcommit-style layout:** Hook templates live in `templates/hooks/` (was `lib/rails_git_hooks/templates/`). `rake sync_hooks` copies them to `hooks/` for manual install.
|
|
32
|
+
- **Constants:** Extracted `lib/rails_git_hooks/constants.rb` (GEM_ROOT, HOOKS_DIR, DEFAULT_HOOKS, FEATURE_FLAG_FILES). Installer and CLI use it. Single source of truth; no config file.
|
|
33
|
+
- Gemspec includes `templates/**/*`. Version set to 0.7.0.
|
|
34
|
+
|
|
35
|
+
## [0.6.1]
|
|
8
36
|
|
|
9
37
|
### Changed
|
|
10
38
|
|
|
11
|
-
- **Default install** now installs **commit-msg** and **pre-commit** only (Jira ticket prefix + default-branch protection
|
|
39
|
+
- **Default install** now installs **commit-msg** and **pre-commit** only (Jira ticket prefix + default-branch protection; RuboCop opt-in). Pre-push remains opt-in: `rails_git_hooks install pre-push`.
|
|
12
40
|
- README: quick start and commands table updated for default (commit-msg + pre-commit); Jira project key / `JIRA_PROJECT_KEY` for manual install; pre-push install instruction.
|
|
13
41
|
|
|
14
42
|
## [0.6.0]
|
data/README.md
CHANGED
|
@@ -1,164 +1,230 @@
|
|
|
1
|
-
# Git Hooks
|
|
1
|
+
# Rails Git Hooks
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/rails_git_hooks)
|
|
4
4
|
[](https://github.com/NikitaNazarov1/rails_git_hooks/actions/workflows/tests.yml?query=branch%3Amain)
|
|
5
5
|
[](https://github.com/NikitaNazarov1/rails_git_hooks/actions/workflows/rubocop.yml?query=branch%3Amain)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Git hooks for Rails and Ruby projects with built-in defaults, optional sparse overrides, and Overcommit-style per-check policies.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## What changed
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The project now uses a **code-first hook runtime**:
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| **pre-push** | Runs the full test suite (`bundle exec rspec`) before push; aborts push if tests fail. |
|
|
13
|
+
- checks declare their defaults in Ruby
|
|
14
|
+
- hook scripts are thin bootstraps
|
|
15
|
+
- `.rails_git_hooks.yml` is optional and contains only overrides
|
|
16
|
+
- checks can be configured with `enabled`, `quiet`, `on_fail`, `on_warn`, `on_missing_dependency`, `include`, and `exclude`
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
## Included hooks
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
| Git hook | Purpose |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `commit-msg` | Prefix commit messages with Jira-style ticket IDs from the current branch |
|
|
23
|
+
| `pre-commit` | Run commit-time checks like branch protection, debugger detection, format validation, and optional code quality checks |
|
|
24
|
+
| `pre-push` | Run the test suite before push |
|
|
22
25
|
|
|
23
26
|
## Quick start
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
### 1. Install the gem
|
|
26
29
|
|
|
27
30
|
```bash
|
|
28
31
|
gem install rails_git_hooks
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
Or
|
|
34
|
+
Or add it to your `Gemfile`:
|
|
32
35
|
|
|
33
36
|
```ruby
|
|
34
37
|
gem "rails_git_hooks"
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
Then:
|
|
40
|
+
Then install dependencies:
|
|
38
41
|
|
|
39
42
|
```bash
|
|
40
43
|
bundle install
|
|
41
|
-
bundle exec rails_git_hooks install
|
|
42
44
|
```
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
### 2. Install hooks
|
|
47
|
+
|
|
48
|
+
From your project root:
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
```bash
|
|
51
|
+
bundle exec rails_git_hooks install
|
|
52
|
+
```
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
This installs `commit-msg` and `pre-commit` by default.
|
|
55
|
+
|
|
56
|
+
### 3. Inspect available checks
|
|
49
57
|
|
|
50
58
|
```bash
|
|
51
|
-
|
|
52
|
-
# or
|
|
53
|
-
export GIT_HOOKS_JIRA_PROJECT=MYPROJ
|
|
54
|
-
rails_git_hooks install
|
|
59
|
+
bundle exec rails_git_hooks list
|
|
55
60
|
```
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
### 4. Override behavior only when needed
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
`rails_git_hooks install pre-push`
|
|
64
|
+
Enable RuboCop:
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
```bash
|
|
67
|
+
bundle exec rails_git_hooks enable rubocop-check
|
|
68
|
+
```
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
Make debugger statements fail instead of warn:
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
```bash
|
|
73
|
+
bundle exec rails_git_hooks set debugger-check on_fail fail
|
|
74
|
+
```
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
Disable migrations warnings:
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
| `rails_git_hooks list` | List available hook names. |
|
|
74
|
-
| `rails_git_hooks disable HOOK [HOOK...] [whitespace-check]` | Disable hooks (use `*` for all) or the whitespace-check. |
|
|
75
|
-
| `rails_git_hooks enable HOOK [HOOK...] [whitespace-check]` | Re-enable hooks or enable whitespace-check. |
|
|
76
|
-
| `rails_git_hooks disabled` | Show which hooks are currently disabled. |
|
|
78
|
+
```bash
|
|
79
|
+
bundle exec rails_git_hooks disable migrations-check
|
|
80
|
+
```
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
Show effective config:
|
|
79
83
|
|
|
80
84
|
```bash
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
bundle exec rails_git_hooks show-config
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Config model
|
|
89
|
+
|
|
90
|
+
You do **not** need a config file for the defaults to work.
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
rails_git_hooks install pre-commit commit-msg --jira APD
|
|
92
|
+
If you want overrides, create one:
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
rails_git_hooks
|
|
94
|
+
```bash
|
|
95
|
+
bundle exec rails_git_hooks init
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This creates `.rails_git_hooks.yml`. The file is sparse: only your changes are stored there.
|
|
89
99
|
|
|
90
|
-
|
|
91
|
-
rails_git_hooks disable *
|
|
100
|
+
Example:
|
|
92
101
|
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
```yaml
|
|
103
|
+
PreCommit:
|
|
104
|
+
DebuggerCheck:
|
|
105
|
+
on_fail: fail
|
|
95
106
|
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
RuboCop:
|
|
108
|
+
enabled: true
|
|
109
|
+
quiet: true
|
|
110
|
+
include:
|
|
111
|
+
- "app/**/*.rb"
|
|
112
|
+
- "lib/**/*.rb"
|
|
113
|
+
exclude:
|
|
114
|
+
- "db/schema.rb"
|
|
98
115
|
```
|
|
99
116
|
|
|
100
|
-
|
|
117
|
+
### Supported per-check options
|
|
101
118
|
|
|
102
|
-
|
|
119
|
+
| Option | Meaning |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `enabled` | Enable or disable a check |
|
|
122
|
+
| `quiet` | Hide normal output unless the check warns or fails |
|
|
123
|
+
| `on_fail` | Map a check failure to `fail`, `warn`, or `pass` |
|
|
124
|
+
| `on_warn` | Map a warning to `warn`, `fail`, or `pass` |
|
|
125
|
+
| `on_missing_dependency` | Control behavior when required tools/libraries are missing |
|
|
126
|
+
| `include` | File paths or glob patterns that the check should apply to |
|
|
127
|
+
| `exclude` | File paths or glob patterns to remove from the included set |
|
|
128
|
+
| `command` | Override the command used by command-based checks |
|
|
103
129
|
|
|
104
|
-
##
|
|
130
|
+
## Dependency model
|
|
105
131
|
|
|
106
|
-
|
|
132
|
+
Checks can declare dependencies such as:
|
|
107
133
|
|
|
108
|
-
|
|
134
|
+
- executables like `bundle`
|
|
135
|
+
- Ruby libraries like `rubocop`
|
|
136
|
+
- required files
|
|
109
137
|
|
|
110
|
-
|
|
138
|
+
If a dependency is missing, the runner produces a structured result and applies the check’s `on_missing_dependency` policy. This makes missing-tool behavior consistent across all checks.
|
|
111
139
|
|
|
112
|
-
|
|
113
|
-
- You run: `git commit -m 'fix bug'`
|
|
114
|
-
- Result: **`[APD-1234] fix bug`**
|
|
140
|
+
## Default checks
|
|
115
141
|
|
|
116
|
-
|
|
142
|
+
### `commit-msg`
|
|
117
143
|
|
|
118
|
-
|
|
144
|
+
- `jira-prefix`
|
|
145
|
+
- enabled by default
|
|
146
|
+
- prefixes commit messages with `[TICKET-123]` when the branch name contains a Jira-style ticket ID
|
|
119
147
|
|
|
120
|
-
### pre-commit
|
|
148
|
+
### `pre-commit`
|
|
121
149
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
150
|
+
- `default-branch`
|
|
151
|
+
- enabled by default
|
|
152
|
+
- fails on `master` / `main`
|
|
125
153
|
|
|
126
|
-
|
|
154
|
+
- `debugger-check`
|
|
155
|
+
- enabled by default
|
|
156
|
+
- warns on debugger statements in Ruby, JavaScript/TypeScript, and Python
|
|
127
157
|
|
|
128
|
-
|
|
158
|
+
- `yaml-format-check`
|
|
159
|
+
- enabled by default
|
|
160
|
+
- warns on invalid `.yml` / `.yaml`
|
|
129
161
|
|
|
130
|
-
|
|
162
|
+
- `json-format-check`
|
|
163
|
+
- enabled by default
|
|
164
|
+
- warns on invalid `.json`
|
|
131
165
|
|
|
132
|
-
|
|
166
|
+
- `migrations-check`
|
|
167
|
+
- enabled by default
|
|
168
|
+
- warns when schema/data schema files appear to be missing after migrations
|
|
133
169
|
|
|
134
|
-
|
|
170
|
+
- `whitespace-check`
|
|
171
|
+
- disabled by default
|
|
172
|
+
- fails on trailing whitespace and merge conflict markers
|
|
135
173
|
|
|
136
|
-
|
|
174
|
+
- `rubocop-check`
|
|
175
|
+
- disabled by default
|
|
176
|
+
- runs RuboCop on staged Ruby files
|
|
177
|
+
- default dependency behavior warns if `rubocop` is missing
|
|
137
178
|
|
|
138
|
-
|
|
179
|
+
### `pre-push`
|
|
139
180
|
|
|
140
|
-
|
|
181
|
+
- `run-tests`
|
|
182
|
+
- enabled by default when `pre-push` is installed
|
|
183
|
+
- runs `bundle exec rspec`
|
|
141
184
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
|
145
|
-
|
|
146
|
-
| [
|
|
185
|
+
## CLI reference
|
|
186
|
+
|
|
187
|
+
| Command | Description |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `rails_git_hooks install [HOOK...]` | Install hook scripts into `.git/hooks` |
|
|
190
|
+
| `rails_git_hooks list` | List available git hooks and check keys |
|
|
191
|
+
| `rails_git_hooks init` | Create `.rails_git_hooks.yml` |
|
|
192
|
+
| `rails_git_hooks enable CHECK_NAME` | Set `enabled: true` for a check override |
|
|
193
|
+
| `rails_git_hooks disable CHECK_NAME` | Set `enabled: false` for a check override |
|
|
194
|
+
| `rails_git_hooks set CHECK_NAME OPTION VALUE` | Set a single override option |
|
|
195
|
+
| `rails_git_hooks show-config` | Print effective merged configuration |
|
|
147
196
|
|
|
148
|
-
|
|
197
|
+
Examples:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
rails_git_hooks install
|
|
201
|
+
rails_git_hooks install pre-push
|
|
202
|
+
rails_git_hooks enable rubocop-check
|
|
203
|
+
rails_git_hooks disable migrations-check
|
|
204
|
+
rails_git_hooks set debugger-check on_fail fail
|
|
205
|
+
rails_git_hooks set rubocop-check quiet true
|
|
206
|
+
rails_git_hooks show-config
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Manual installation
|
|
210
|
+
|
|
211
|
+
From your project (with the gem in the Gemfile or installed), run:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
bundle exec rails_git_hooks install
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
This installs the thin hook bootstraps and the embedded `rails_git_hooks` runtime into `.git/hooks/`.
|
|
149
218
|
|
|
150
219
|
## Development
|
|
151
220
|
|
|
152
221
|
```bash
|
|
153
222
|
bundle install
|
|
154
|
-
bundle exec rake # run specs
|
|
223
|
+
bundle exec rake # run specs
|
|
155
224
|
bundle exec rake build # build the gem
|
|
156
|
-
bundle exec rake install # install
|
|
157
|
-
bundle exec rake sync_hooks # copy templates to hooks/
|
|
225
|
+
bundle exec rake install # install locally
|
|
158
226
|
```
|
|
159
227
|
|
|
160
|
-
---
|
|
161
|
-
|
|
162
228
|
## License
|
|
163
229
|
|
|
164
230
|
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
|
|
7
|
+
module GitHooks
|
|
8
|
+
module Checks
|
|
9
|
+
class Base
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :definition
|
|
12
|
+
|
|
13
|
+
def check_definition(key:, hook:, description:, config_name: name.split('::').last, **options)
|
|
14
|
+
@definition = CheckDefinition.new(
|
|
15
|
+
key: key,
|
|
16
|
+
config_name: config_name,
|
|
17
|
+
hook: hook,
|
|
18
|
+
klass: self,
|
|
19
|
+
description: description,
|
|
20
|
+
**options
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
attr_reader :config, :context
|
|
26
|
+
|
|
27
|
+
def initialize(config:, context:)
|
|
28
|
+
@config = config
|
|
29
|
+
@context = context
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def repo
|
|
35
|
+
context.fetch(:repo)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def applicable_files
|
|
39
|
+
context.fetch(:applicable_files, [])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def argv
|
|
43
|
+
context.fetch(:argv, [])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def stdin
|
|
47
|
+
context.fetch(:stdin, '')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def capture(*command)
|
|
51
|
+
Open3.capture2e(*command, chdir: repo.root)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module CommitMsg
|
|
6
|
+
class JiraPrefix < Base
|
|
7
|
+
TICKET_PATTERN = /([A-Z]{2,5}-\d+)/.freeze
|
|
8
|
+
|
|
9
|
+
check_definition key: 'jira-prefix',
|
|
10
|
+
hook: :commit_msg,
|
|
11
|
+
description: 'Prefix commit messages with ticket id from branch'
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
message_file = argv.first
|
|
15
|
+
return CheckResult.pass unless message_file && File.file?(message_file)
|
|
16
|
+
|
|
17
|
+
branch = repo.current_branch
|
|
18
|
+
ticket = branch[TICKET_PATTERN, 1]
|
|
19
|
+
return CheckResult.pass unless ticket
|
|
20
|
+
|
|
21
|
+
message = File.read(message_file)
|
|
22
|
+
prefix = "[#{ticket}]"
|
|
23
|
+
return CheckResult.pass if message.lstrip.start_with?(prefix)
|
|
24
|
+
|
|
25
|
+
File.write(message_file, "#{prefix} #{message}")
|
|
26
|
+
CheckResult.pass
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class DebuggerCheck < Base
|
|
7
|
+
DEBUGGER_PATTERNS = {
|
|
8
|
+
'.rb' => [/\bbinding\.pry\b/, /\bbinding\.irb\b/, /\bdebugger\b/, /\bbyebug\b/],
|
|
9
|
+
'.js' => [/\bdebugger\s*;?/],
|
|
10
|
+
'.jsx' => [/\bdebugger\s*;?/],
|
|
11
|
+
'.ts' => [/\bdebugger\s*;?/],
|
|
12
|
+
'.tsx' => [/\bdebugger\s*;?/],
|
|
13
|
+
'.mjs' => [/\bdebugger\s*;?/],
|
|
14
|
+
'.cjs' => [/\bdebugger\s*;?/],
|
|
15
|
+
'.py' => [/\bbreakpoint\s*\(\s*\)/, /\bpdb\.set_trace\s*\(\s*\)/, /\bipdb\.set_trace\s*\(\s*\)/]
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
check_definition key: 'debugger-check',
|
|
19
|
+
hook: :pre_commit,
|
|
20
|
+
description: 'Warn on debugger statements',
|
|
21
|
+
file_based: true,
|
|
22
|
+
on_fail: :warn
|
|
23
|
+
|
|
24
|
+
def run
|
|
25
|
+
warnings = []
|
|
26
|
+
|
|
27
|
+
applicable_files.each do |path|
|
|
28
|
+
next unless File.file?(path)
|
|
29
|
+
|
|
30
|
+
patterns = DEBUGGER_PATTERNS[File.extname(path)]
|
|
31
|
+
next unless patterns
|
|
32
|
+
|
|
33
|
+
File.read(path).lines.each_with_index do |line, index|
|
|
34
|
+
warnings << "#{path}:#{index + 1}: debugger statement" if patterns.any? { |pattern| line.match?(pattern) }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
warnings.empty? ? CheckResult.pass : CheckResult.fail(messages: warnings.uniq)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class DefaultBranch < Base
|
|
7
|
+
check_definition key: 'default-branch',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Prevent commits on default branch'
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
branch = repo.current_branch
|
|
13
|
+
return CheckResult.pass unless %w[master main].include?(branch)
|
|
14
|
+
|
|
15
|
+
CheckResult.fail(messages: ["Commits on '#{branch}' are not allowed. Create a feature branch."])
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class JSONFormatCheck < Base
|
|
7
|
+
check_definition key: 'json-format-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Warn on invalid JSON',
|
|
10
|
+
file_based: true,
|
|
11
|
+
on_fail: :warn
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
warnings = []
|
|
15
|
+
|
|
16
|
+
applicable_files.each do |path|
|
|
17
|
+
next unless File.file?(path)
|
|
18
|
+
next unless File.extname(path) == '.json'
|
|
19
|
+
|
|
20
|
+
JSON.parse(File.read(path))
|
|
21
|
+
rescue JSON::ParserError => e
|
|
22
|
+
warnings << "#{path}: #{e.message}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
warnings.empty? ? CheckResult.pass : CheckResult.fail(messages: warnings)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class MigrationsCheck < Base
|
|
7
|
+
check_definition key: 'migrations-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Warn on missing schema files after migrations',
|
|
10
|
+
file_based: true,
|
|
11
|
+
on_fail: :warn
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
messages = []
|
|
15
|
+
migration_files = applicable_files.grep(%r{\Adb/migrate/.*\.rb\z})
|
|
16
|
+
schema_staged = applicable_files.include?('db/schema.rb') || applicable_files.include?('db/structure.sql')
|
|
17
|
+
|
|
18
|
+
if migration_files.any? && !schema_staged
|
|
19
|
+
messages << 'Migration file(s) are staged but neither db/schema.rb nor db/structure.sql is staged.'
|
|
20
|
+
messages << 'Run `rails db:migrate` and add db/schema.rb (or db/structure.sql) to your commit.'
|
|
21
|
+
migration_files.each { |path| messages << "- #{path}" }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
data_migration_files = applicable_files.grep(%r{\Adb/(data/|data_migrate/).*\.rb\z})
|
|
25
|
+
data_schema_staged = applicable_files.include?('db/data_schema.rb')
|
|
26
|
+
if data_migration_files.any? && !data_schema_staged
|
|
27
|
+
messages << 'Data migration file(s) are staged but db/data_schema.rb is not staged.'
|
|
28
|
+
messages << 'Run your data migrate task and add db/data_schema.rb to your commit.'
|
|
29
|
+
data_migration_files.each { |path| messages << "- #{path}" }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
messages.empty? ? CheckResult.pass : CheckResult.fail(messages: messages)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class RuboCop < Base
|
|
7
|
+
check_definition key: 'rubocop-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Run RuboCop on staged Ruby files',
|
|
10
|
+
file_based: true,
|
|
11
|
+
enabled: false,
|
|
12
|
+
quiet: true,
|
|
13
|
+
dependencies: { 'executables' => ['bundle'], 'libraries' => ['rubocop'] },
|
|
14
|
+
command: %w[bundle exec rubocop],
|
|
15
|
+
install_hint: 'Add `gem "rubocop"` to your Gemfile and run bundle install'
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
ruby_files = applicable_files.select { |path| File.extname(path) == '.rb' && File.file?(path) }
|
|
19
|
+
return CheckResult.pass if ruby_files.empty?
|
|
20
|
+
|
|
21
|
+
output, status = capture(*Array(config['command']), *ruby_files)
|
|
22
|
+
return CheckResult.pass if status.success?
|
|
23
|
+
|
|
24
|
+
messages = output.split("\n").map(&:rstrip).reject(&:empty?)
|
|
25
|
+
CheckResult.fail(messages: messages)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class WhitespaceCheck < Base
|
|
7
|
+
check_definition key: 'whitespace-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Reject trailing whitespace and conflict markers',
|
|
10
|
+
file_based: true,
|
|
11
|
+
enabled: false
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
errors = []
|
|
15
|
+
|
|
16
|
+
applicable_files.each do |path|
|
|
17
|
+
next unless File.file?(path)
|
|
18
|
+
|
|
19
|
+
File.read(path).lines.each_with_index do |line, index|
|
|
20
|
+
errors << "#{path}:#{index + 1}: trailing whitespace" if line.match?(/[ \t]\z/)
|
|
21
|
+
stripped = line.strip
|
|
22
|
+
errors << "#{path}:#{index + 1}: conflict marker" if stripped.start_with?('<<<<<<<', '=======', '>>>>>>>')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
errors.empty? ? CheckResult.pass : CheckResult.fail(messages: errors.uniq)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|