rails_git_hooks 0.6.0 → 0.7.0
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 +24 -1
- data/README.md +72 -65
- data/lib/rails_git_hooks/cli.rb +34 -32
- data/lib/rails_git_hooks/constants.rb +21 -0
- data/lib/rails_git_hooks/installer.rb +62 -21
- data/lib/rails_git_hooks/version.rb +1 -1
- data/lib/rails_git_hooks.rb +1 -0
- data/templates/hooks/commit-msg +23 -0
- data/templates/hooks/pre-commit +27 -0
- data/{lib/rails_git_hooks/templates → templates/hooks}/pre-push +7 -5
- data/templates/shared/commit_msg/jira_prefix.rb +20 -0
- data/templates/shared/pre_commit/debugger_check.rb +48 -0
- data/templates/shared/pre_commit/default_branch.rb +9 -0
- data/templates/shared/pre_commit/rubocop_check.rb +24 -0
- data/templates/shared/pre_commit/whitespace_check.rb +25 -0
- data/templates/shared/pre_push/run_tests.rb +9 -0
- metadata +11 -4
- data/lib/rails_git_hooks/templates/commit-msg +0 -32
- data/lib/rails_git_hooks/templates/pre-commit +0 -58
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b990407e471e8f6dddf8df8741a8ac6de92955bc44470b1b45a19b93644b542
|
|
4
|
+
data.tar.gz: ed3f378f82db9a1dc81dcf58d90f02d12da0ff32c05697ecc2f1dbb92f8db2ca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b1aa8a31af84e697e05f56d94ff3427a0afa82e0dfabe4de21e5f0ec865f7ba6c7ddd0537f058e852281a415f68b26a063fd6ef8e71f0d0f1a0b7f9c718aa04
|
|
7
|
+
data.tar.gz: 966f4fbd5dcfac4ce1e4a9ad1d8a3f8209f0d2885030ece2d916c5598e2324aeac348f7bc8e9690e60bd3676fc995e264e0c2e2b1fd80e51cd1563d4cf3bb4d0
|
data/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,30 @@ 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.0] (latest)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Pre-commit debugger check** — Warns (does not block) when staged files contain debugger statements: Ruby (`binding.pry`, `debugger`, `byebug`, `binding.irb`), JavaScript/TypeScript (`.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs` — `debugger`), Python (`breakpoint()`, `pdb.set_trace()`, `ipdb.set_trace()`). On by default with pre-commit.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **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.
|
|
16
|
+
- **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.
|
|
17
|
+
- Gemspec includes `templates/**/*`. Version set to 0.7.0.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **Hook scripts** — `RailsGitHooks::GIT_DIR` was set inside a `module` body, where the script’s local `git_dir` is out of scope (Ruby scope gate), causing `NameError` when hooks ran. All three hooks (commit-msg, pre-commit, pre-push) now set the constant via `RailsGitHooks.const_set(:GIT_DIR, git_dir.freeze)` from the script scope.
|
|
22
|
+
|
|
23
|
+
## [0.6.1]
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **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`.
|
|
28
|
+
- 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.
|
|
29
|
+
|
|
30
|
+
## [0.6.0]
|
|
8
31
|
|
|
9
32
|
### Added
|
|
10
33
|
|
data/README.md
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
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
|
+
Most useful git hooks for Rails and Ruby. Install only what you need. Turn hooks off anytime without uninstalling.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## What
|
|
11
|
+
## What’s included
|
|
12
12
|
|
|
13
|
-
| Hook |
|
|
14
|
-
|
|
15
|
-
| **commit-msg** |
|
|
16
|
-
| **pre-commit** | Blocks commits to `master`/`main
|
|
17
|
-
| **pre-push** | Runs
|
|
13
|
+
| Hook | Description |
|
|
14
|
+
|------|-------------|
|
|
15
|
+
| **commit-msg** | Adds `[TICKET-123]` to commit messages when your branch name contains a Jira ticket. |
|
|
16
|
+
| **pre-commit** | Blocks commits to `master`/`main`. Warns about debugger statements (Ruby, JS/TS, Python). Optional: RuboCop, trailing-whitespace/conflict checks. |
|
|
17
|
+
| **pre-push** | Runs `bundle exec rspec` before push and blocks push if tests fail. |
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- **Installed by default:** `commit-msg` and `pre-commit` (branch protection + debugger warnings; RuboCop and whitespace checks are off).
|
|
20
|
+
- **Optional:** `pre-push`, RuboCop, and whitespace/conflict checks — enable when you want them.
|
|
20
21
|
|
|
21
22
|
---
|
|
22
23
|
|
|
23
24
|
## Quick start
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
### 1. Install the gem
|
|
27
|
+
|
|
28
|
+
**Standalone:**
|
|
26
29
|
|
|
27
30
|
```bash
|
|
28
31
|
gem install rails_git_hooks
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
**With Bundler** — add to your `Gemfile`:
|
|
32
35
|
|
|
33
36
|
```ruby
|
|
34
37
|
gem "rails_git_hooks"
|
|
@@ -38,56 +41,57 @@ Then:
|
|
|
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 (inside the git repo):
|
|
45
49
|
|
|
46
50
|
```bash
|
|
47
|
-
rails_git_hooks install
|
|
48
|
-
# or
|
|
49
|
-
export GIT_HOOKS_JIRA_PROJECT=MYPROJ
|
|
50
|
-
rails_git_hooks install
|
|
51
|
+
bundle exec rails_git_hooks install
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
This installs **commit-msg** and **pre-commit** (default-branch protection only). No Jira project key needed — the hook detects ticket IDs like `APD-123` or `PROJ-456` from the branch name.
|
|
55
|
+
|
|
56
|
+
### 3. Optional: add more
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Run tests before every push
|
|
60
|
+
rails_git_hooks install pre-push
|
|
61
|
+
|
|
62
|
+
# Run RuboCop on staged .rb files before commit
|
|
63
|
+
rails_git_hooks enable rubocop-check
|
|
64
|
+
|
|
65
|
+
# Reject trailing whitespace and conflict markers in staged files
|
|
66
|
+
rails_git_hooks enable whitespace-check
|
|
67
|
+
```
|
|
54
68
|
|
|
55
|
-
|
|
69
|
+
**Tip:** If a hook doesn’t run, make it executable: `chmod +x .git/hooks/<hook-name>`
|
|
56
70
|
|
|
57
71
|
---
|
|
58
72
|
|
|
59
|
-
##
|
|
73
|
+
## Command reference
|
|
60
74
|
|
|
61
|
-
|
|
75
|
+
All commands are run from the project root.
|
|
62
76
|
|
|
63
77
|
| Command | Description |
|
|
64
78
|
|---------|-------------|
|
|
65
|
-
| `rails_git_hooks install [HOOK...]
|
|
79
|
+
| `rails_git_hooks install [HOOK...]` | Install hooks. No arguments = install default (commit-msg + pre-commit). |
|
|
66
80
|
| `rails_git_hooks list` | List available hook names. |
|
|
67
|
-
| `rails_git_hooks disable HOOK [
|
|
68
|
-
| `rails_git_hooks enable HOOK [
|
|
69
|
-
| `rails_git_hooks disabled` | Show
|
|
81
|
+
| `rails_git_hooks disable HOOK [...]` | Disable hooks or options (use `*` for all). |
|
|
82
|
+
| `rails_git_hooks enable HOOK [...]` | Re-enable hooks or enable optional checks. |
|
|
83
|
+
| `rails_git_hooks disabled` | Show currently disabled hooks. |
|
|
70
84
|
|
|
71
|
-
**
|
|
85
|
+
**Common examples:**
|
|
72
86
|
|
|
73
87
|
```bash
|
|
74
|
-
#
|
|
75
|
-
rails_git_hooks install
|
|
76
|
-
|
|
77
|
-
#
|
|
78
|
-
rails_git_hooks
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
rails_git_hooks disable pre-commit
|
|
82
|
-
|
|
83
|
-
# Disable all hooks
|
|
84
|
-
rails_git_hooks disable *
|
|
85
|
-
|
|
86
|
-
# Turn them back on
|
|
87
|
-
rails_git_hooks enable pre-commit
|
|
88
|
-
|
|
89
|
-
# Enable rejection of trailing whitespace and conflict markers in staged files (off by default)
|
|
90
|
-
rails_git_hooks enable whitespace-check
|
|
88
|
+
rails_git_hooks install # default hooks
|
|
89
|
+
rails_git_hooks install pre-push # add pre-push
|
|
90
|
+
rails_git_hooks disable pre-commit # turn off pre-commit temporarily
|
|
91
|
+
rails_git_hooks disable * # turn off all
|
|
92
|
+
rails_git_hooks enable pre-commit # turn pre-commit back on
|
|
93
|
+
rails_git_hooks enable rubocop-check # run RuboCop on staged .rb files
|
|
94
|
+
rails_git_hooks enable whitespace-check # reject trailing ws & conflict markers
|
|
91
95
|
```
|
|
92
96
|
|
|
93
97
|
Disabled state is stored in `.git/rails_git_hooks_disabled` and persists until you run `enable`.
|
|
@@ -98,45 +102,48 @@ Disabled state is stored in `.git/rails_git_hooks_disabled` and persists until y
|
|
|
98
102
|
|
|
99
103
|
### commit-msg — Jira ticket prefix
|
|
100
104
|
|
|
101
|
-
If
|
|
105
|
+
**What it does:** If the branch name contains a Jira-style ticket (e.g. `task/APD-1234/fix-bug`), the hook prepends `[APD-1234]` to the commit message — unless the message already starts with that format. Works with any project key (2–5 letters + digits); no config.
|
|
102
106
|
|
|
103
|
-
**Example
|
|
107
|
+
**Example:**
|
|
104
108
|
|
|
105
109
|
- Branch: `task/APD-1234/fix-bug`
|
|
106
|
-
-
|
|
110
|
+
- Command: `git commit -m 'fix bug'`
|
|
107
111
|
- Result: **`[APD-1234] fix bug`**
|
|
108
112
|
|
|
109
|
-
Set the Jira project key at install time with `--jira PROJECT` or `GIT_HOOKS_JIRA_PROJECT`.
|
|
110
|
-
|
|
111
113
|
---
|
|
112
114
|
|
|
113
|
-
### pre-commit —
|
|
115
|
+
### pre-commit — Branch protection and optional checks
|
|
116
|
+
|
|
117
|
+
**Always on (when installed):**
|
|
118
|
+
|
|
119
|
+
- Blocks commits to `master` or `main`. You must commit from a feature branch.
|
|
120
|
+
- **Debugger check** — Warns (does not block) when staged files contain debugger statements: Ruby (`binding.pry`, `debugger`, `byebug`, `binding.irb`), JavaScript/TypeScript (`.js`, `.jsx`, `.ts`, `.tsx` — `debugger`), Python (`breakpoint()`, `pdb.set_trace()`, `ipdb.set_trace()`).
|
|
114
121
|
|
|
115
|
-
|
|
116
|
-
2. **Runs RuboCop** on staged `.rb` files. If there are offenses, the commit is aborted.
|
|
117
|
-
3. **Trailing whitespace / conflict markers** (off by default) — When enabled, rejects commits that add trailing spaces/tabs or `<<<<<<<` / `=======` / `>>>>>>>` in staged files. Enable with: `rails_git_hooks enable whitespace-check`. Disable with: `rails_git_hooks disable whitespace-check`.
|
|
122
|
+
**Optional (off by default):**
|
|
118
123
|
|
|
119
|
-
|
|
124
|
+
1. **RuboCop** — Run RuboCop on staged `.rb` files; commit fails if there are offenses.
|
|
125
|
+
`rails_git_hooks enable rubocop-check` / `disable rubocop-check`. Requires the `rubocop` gem.
|
|
126
|
+
|
|
127
|
+
2. **Whitespace & conflict markers** — Reject commits that add trailing spaces/tabs or `<<<<<<<` / `=======` / `>>>>>>>` in staged files.
|
|
128
|
+
`rails_git_hooks enable whitespace-check` / `disable whitespace-check`.
|
|
120
129
|
|
|
121
130
|
---
|
|
122
131
|
|
|
123
132
|
### pre-push — Run tests before push
|
|
124
133
|
|
|
125
|
-
Runs `bundle exec rspec` before every `git push`. If the
|
|
126
|
-
|
|
127
|
-
Requires the `rspec` gem (or for Minitest, edit the hook to use `bundle exec rake test`). If the hook doesn’t run, ensure it’s executable: `chmod +x .git/hooks/pre-push`.
|
|
134
|
+
Runs `bundle exec rspec` before every `git push`. If the suite fails, the push is aborted. Not installed by default; add with `rails_git_hooks install pre-push`. For Minitest, edit the hook to use `bundle exec rake test`.
|
|
128
135
|
|
|
129
136
|
---
|
|
130
137
|
|
|
131
138
|
## Manual installation (without the gem)
|
|
132
139
|
|
|
133
|
-
|
|
140
|
+
Copy the **entire** `hooks/` directory into your repo’s `.git/hooks/` (so the hook scripts and the `pre_commit/`, `commit_msg/`, `pre_push/` subdirs are all under `.git/hooks/`). Run `rake sync_hooks` to regenerate `hooks/` from `templates/hooks/` and `templates/shared/`.
|
|
134
141
|
|
|
135
|
-
|
|
|
136
|
-
|
|
137
|
-
| [commit-msg](hooks/commit-msg) |
|
|
138
|
-
| [pre-commit](hooks/pre-commit) |
|
|
139
|
-
| [pre-push](hooks/pre-push) | Runs `bundle exec rspec`; edit
|
|
142
|
+
| Script | Notes |
|
|
143
|
+
|--------|--------|
|
|
144
|
+
| [commit-msg](hooks/commit-msg) | Jira-style ticket prefix; no config. |
|
|
145
|
+
| [pre-commit](hooks/pre-commit) | Branch protection + debugger warnings; optional RuboCop (requires `rubocop` gem). |
|
|
146
|
+
| [pre-push](hooks/pre-push) | Runs `bundle exec rspec`; edit for Minitest if needed. |
|
|
140
147
|
|
|
141
148
|
---
|
|
142
149
|
|
|
@@ -144,10 +151,10 @@ If you don’t want to use the gem, copy the scripts from `hooks/` into `.git/ho
|
|
|
144
151
|
|
|
145
152
|
```bash
|
|
146
153
|
bundle install
|
|
147
|
-
bundle exec rake # run specs
|
|
154
|
+
bundle exec rake # run specs
|
|
148
155
|
bundle exec rake build # build the gem
|
|
149
|
-
bundle exec rake install # install
|
|
150
|
-
bundle exec rake sync_hooks # copy templates
|
|
156
|
+
bundle exec rake install # install locally
|
|
157
|
+
bundle exec rake sync_hooks # copy templates (hooks + shared subdirs) → hooks/
|
|
151
158
|
```
|
|
152
159
|
|
|
153
160
|
---
|
data/lib/rails_git_hooks/cli.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'rails_git_hooks'
|
|
4
|
-
require 'optparse'
|
|
5
4
|
|
|
6
5
|
module GitHooks
|
|
7
6
|
class CLI
|
|
7
|
+
FEATURE_FLAG_TOKENS = GitHooks::Constants::FEATURE_FLAG_FILES.keys.freeze
|
|
8
|
+
|
|
8
9
|
def self.run(argv = ARGV)
|
|
9
10
|
new.run(argv)
|
|
10
11
|
end
|
|
@@ -33,14 +34,8 @@ module GitHooks
|
|
|
33
34
|
private
|
|
34
35
|
|
|
35
36
|
def run_install(args)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
opts.on('--jira PROJECT', 'Jira project key (e.g. APD)') { |v| jira = v }
|
|
39
|
-
end.parse!(args)
|
|
40
|
-
hooks = args
|
|
41
|
-
|
|
42
|
-
installer = Installer.new(jira_project: jira)
|
|
43
|
-
installed = installer.install(*hooks)
|
|
37
|
+
installer = Installer.new
|
|
38
|
+
installed = installer.install(*args)
|
|
44
39
|
puts "Installed hooks: #{installed.join(', ')}"
|
|
45
40
|
rescue GitHooks::Error => e
|
|
46
41
|
warn "Error: #{e.message}"
|
|
@@ -48,46 +43,52 @@ module GitHooks
|
|
|
48
43
|
end
|
|
49
44
|
|
|
50
45
|
def run_list
|
|
51
|
-
|
|
52
|
-
hooks = Dir.children(dir).select { |f| File.file?(File.join(dir, f)) }
|
|
53
|
-
puts "Available hooks: #{hooks.join(', ')}"
|
|
46
|
+
puts "Available hooks: #{Installer.available_hook_names.join(', ')}"
|
|
54
47
|
end
|
|
55
48
|
|
|
56
|
-
def run_disable(args)
|
|
57
|
-
tokens = args
|
|
49
|
+
def run_disable(args)
|
|
50
|
+
tokens = parse_tokens(args)
|
|
58
51
|
if tokens.empty?
|
|
59
|
-
warn 'Usage: rails_git_hooks disable HOOK [HOOK...] [whitespace-check]'
|
|
52
|
+
warn 'Usage: rails_git_hooks disable HOOK [HOOK...] [whitespace-check] [rubocop-check]'
|
|
60
53
|
warn "Use '*' to disable all hooks."
|
|
61
54
|
exit 1
|
|
62
55
|
end
|
|
63
56
|
installer = Installer.new
|
|
64
|
-
hook_names = tokens
|
|
65
|
-
|
|
57
|
+
hook_names, feature_flags = split_tokens(tokens)
|
|
58
|
+
feature_flags.each { |name| installer.public_send(:"disable_#{name.tr('-', '_')}") }
|
|
66
59
|
installer.disable(*hook_names) if hook_names.any?
|
|
67
|
-
|
|
68
|
-
puts "Disabled: #{disabled.join(', ')}"
|
|
60
|
+
puts "Disabled: #{(hook_names + feature_flags).join(', ')}"
|
|
69
61
|
rescue GitHooks::Error => e
|
|
70
62
|
warn "Error: #{e.message}"
|
|
71
63
|
exit 1
|
|
72
64
|
end
|
|
73
65
|
|
|
74
66
|
def run_enable(args)
|
|
75
|
-
tokens = args
|
|
67
|
+
tokens = parse_tokens(args)
|
|
76
68
|
if tokens.empty?
|
|
77
|
-
warn 'Usage: rails_git_hooks enable HOOK [HOOK...] [whitespace-check]'
|
|
69
|
+
warn 'Usage: rails_git_hooks enable HOOK [HOOK...] [whitespace-check] [rubocop-check]'
|
|
78
70
|
exit 1
|
|
79
71
|
end
|
|
80
72
|
installer = Installer.new
|
|
81
|
-
hook_names = tokens
|
|
82
|
-
|
|
73
|
+
hook_names, feature_flags = split_tokens(tokens)
|
|
74
|
+
feature_flags.each { |name| installer.public_send(:"enable_#{name.tr('-', '_')}") }
|
|
83
75
|
installer.enable(*hook_names) if hook_names.any?
|
|
84
|
-
|
|
85
|
-
puts "Enabled: #{enabled.join(', ')}"
|
|
76
|
+
puts "Enabled: #{(hook_names + feature_flags).join(', ')}"
|
|
86
77
|
rescue GitHooks::Error => e
|
|
87
78
|
warn "Error: #{e.message}"
|
|
88
79
|
exit 1
|
|
89
80
|
end
|
|
90
81
|
|
|
82
|
+
def parse_tokens(args)
|
|
83
|
+
args.reject { |a| a.start_with?('-') }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def split_tokens(tokens)
|
|
87
|
+
feature_flags = tokens & FEATURE_FLAG_TOKENS
|
|
88
|
+
hook_names = tokens - FEATURE_FLAG_TOKENS
|
|
89
|
+
[hook_names, feature_flags]
|
|
90
|
+
end
|
|
91
|
+
|
|
91
92
|
def run_disabled
|
|
92
93
|
installer = Installer.new
|
|
93
94
|
list = installer.disabled_hooks
|
|
@@ -106,17 +107,17 @@ module GitHooks
|
|
|
106
107
|
rails_git_hooks - Install git hooks for Jira commit prefix and RuboCop
|
|
107
108
|
|
|
108
109
|
Usage:
|
|
109
|
-
rails_git_hooks install [HOOK...]
|
|
110
|
-
rails_git_hooks disable HOOK [HOOK...] [whitespace-check] (use * for all hooks)
|
|
111
|
-
rails_git_hooks enable HOOK [HOOK...] [whitespace-check]
|
|
110
|
+
rails_git_hooks install [HOOK...]
|
|
111
|
+
rails_git_hooks disable HOOK [HOOK...] [whitespace-check] [rubocop-check] (use * for all hooks)
|
|
112
|
+
rails_git_hooks enable HOOK [HOOK...] [whitespace-check] [rubocop-check]
|
|
112
113
|
rails_git_hooks disabled
|
|
113
114
|
rails_git_hooks list
|
|
114
115
|
rails_git_hooks --help
|
|
115
116
|
|
|
116
117
|
Commands:
|
|
117
118
|
install Install hooks into current repo's .git/hooks.
|
|
118
|
-
disable Disable hooks or whitespace-check
|
|
119
|
-
enable Re-enable disabled hooks or enable whitespace-check.
|
|
119
|
+
disable Disable hooks or whitespace-check / rubocop-check (pre-commit options).
|
|
120
|
+
enable Re-enable disabled hooks or enable whitespace-check / rubocop-check.
|
|
120
121
|
disabled List currently disabled hooks.
|
|
121
122
|
list List available hook names.
|
|
122
123
|
|
|
@@ -125,8 +126,9 @@ module GitHooks
|
|
|
125
126
|
rails_git_hooks disable pre-commit
|
|
126
127
|
rails_git_hooks disable * # disable all hooks
|
|
127
128
|
rails_git_hooks enable pre-commit
|
|
128
|
-
rails_git_hooks enable whitespace-check #
|
|
129
|
-
rails_git_hooks
|
|
129
|
+
rails_git_hooks enable whitespace-check # trailing ws/conflict markers (off by default)
|
|
130
|
+
rails_git_hooks enable rubocop-check # RuboCop on staged .rb files (off by default)
|
|
131
|
+
rails_git_hooks install commit-msg pre-commit
|
|
130
132
|
HELP
|
|
131
133
|
end
|
|
132
134
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
# Paths and default config (single source of truth).
|
|
5
|
+
module Constants
|
|
6
|
+
GEM_ROOT = File.expand_path('../..', __dir__)
|
|
7
|
+
HOOKS_DIR = File.expand_path('templates/hooks', GEM_ROOT).freeze
|
|
8
|
+
SHARED_DIR = File.expand_path('templates/shared', GEM_ROOT).freeze
|
|
9
|
+
|
|
10
|
+
DISABLED_FILE = 'rails_git_hooks_disabled'
|
|
11
|
+
|
|
12
|
+
# Default hooks when install is run with no arguments.
|
|
13
|
+
DEFAULT_HOOKS = %w[commit-msg pre-commit].freeze
|
|
14
|
+
|
|
15
|
+
# Pre-commit feature flag file names (keys = CLI tokens).
|
|
16
|
+
FEATURE_FLAG_FILES = {
|
|
17
|
+
'whitespace-check' => 'rails_git_hooks_whitespace_check',
|
|
18
|
+
'rubocop-check' => 'rails_git_hooks_rubocop'
|
|
19
|
+
}.freeze
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
3
5
|
module GitHooks
|
|
4
6
|
class Installer
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def initialize(git_dir: nil, jira_project: nil)
|
|
7
|
+
def initialize(git_dir: nil)
|
|
8
8
|
@git_dir = git_dir || find_git_dir
|
|
9
|
-
@jira_project = jira_project || ENV['GIT_HOOKS_JIRA_PROJECT'] || 'APD'
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
def install(*hook_names)
|
|
13
12
|
target_dir = File.join(@git_dir, 'hooks')
|
|
14
13
|
raise GitHooks::Error, "Not a git repository or .git/hooks not found: #{@git_dir}" unless Dir.exist?(target_dir)
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
copy_shared_files(target_dir)
|
|
16
|
+
|
|
17
|
+
hooks = hook_names.empty? ? Constants::DEFAULT_HOOKS : hook_names
|
|
17
18
|
installed = []
|
|
18
19
|
|
|
19
20
|
hooks.each do |name|
|
|
20
|
-
src = File.join(HOOKS_DIR, name)
|
|
21
|
+
src = File.join(Constants::HOOKS_DIR, name)
|
|
21
22
|
next unless File.file?(src)
|
|
22
23
|
|
|
23
24
|
dest = File.join(target_dir, name)
|
|
24
|
-
|
|
25
|
-
content = content.gsub('JIRA_PROJECT_KEY', @jira_project) if name == 'commit-msg'
|
|
26
|
-
write_hook(dest, content)
|
|
25
|
+
write_hook(dest, read_template(name))
|
|
27
26
|
make_executable(dest)
|
|
28
27
|
installed << name
|
|
29
28
|
end
|
|
@@ -31,14 +30,16 @@ module GitHooks
|
|
|
31
30
|
installed
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
def
|
|
35
|
-
Dir.children(HOOKS_DIR).select { |f| File.file?(File.join(HOOKS_DIR, f)) }
|
|
33
|
+
def self.available_hook_names
|
|
34
|
+
Dir.children(Constants::HOOKS_DIR).select { |f| File.file?(File.join(Constants::HOOKS_DIR, f)) }
|
|
36
35
|
end
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
def available_hooks
|
|
38
|
+
self.class.available_hook_names
|
|
39
|
+
end
|
|
39
40
|
|
|
40
41
|
def disabled_file_path
|
|
41
|
-
File.join(@git_dir, DISABLED_FILE)
|
|
42
|
+
File.join(@git_dir, Constants::DISABLED_FILE)
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
def disabled_hooks
|
|
@@ -68,24 +69,51 @@ module GitHooks
|
|
|
68
69
|
hook_names
|
|
69
70
|
end
|
|
70
71
|
|
|
71
|
-
WHITESPACE_CHECK_FILE = 'rails_git_hooks_whitespace_check'
|
|
72
|
-
|
|
73
72
|
def enable_whitespace_check
|
|
74
|
-
|
|
75
|
-
File.write(path, '')
|
|
73
|
+
enable_feature_flag('whitespace-check')
|
|
76
74
|
end
|
|
77
75
|
|
|
78
76
|
def disable_whitespace_check
|
|
79
|
-
|
|
80
|
-
FileUtils.rm_f(path)
|
|
77
|
+
disable_feature_flag('whitespace-check')
|
|
81
78
|
end
|
|
82
79
|
|
|
83
80
|
def whitespace_check_enabled?
|
|
84
|
-
|
|
81
|
+
feature_flag_enabled?('whitespace-check')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def enable_rubocop_check
|
|
85
|
+
enable_feature_flag('rubocop-check')
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def disable_rubocop_check
|
|
89
|
+
disable_feature_flag('rubocop-check')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def rubocop_check_enabled?
|
|
93
|
+
feature_flag_enabled?('rubocop-check')
|
|
85
94
|
end
|
|
86
95
|
|
|
87
96
|
private
|
|
88
97
|
|
|
98
|
+
def enable_feature_flag(name)
|
|
99
|
+
file = Constants::FEATURE_FLAG_FILES[name]
|
|
100
|
+
return unless file
|
|
101
|
+
|
|
102
|
+
File.write(File.join(@git_dir, file), '')
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def disable_feature_flag(name)
|
|
106
|
+
file = Constants::FEATURE_FLAG_FILES[name]
|
|
107
|
+
return unless file
|
|
108
|
+
|
|
109
|
+
FileUtils.rm_f(File.join(@git_dir, file))
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def feature_flag_enabled?(name)
|
|
113
|
+
file = Constants::FEATURE_FLAG_FILES[name]
|
|
114
|
+
file && File.exist?(File.join(@git_dir, file))
|
|
115
|
+
end
|
|
116
|
+
|
|
89
117
|
def find_git_dir
|
|
90
118
|
dir = Dir.pwd
|
|
91
119
|
loop do
|
|
@@ -99,8 +127,21 @@ module GitHooks
|
|
|
99
127
|
end
|
|
100
128
|
end
|
|
101
129
|
|
|
130
|
+
def copy_shared_files(target_dir)
|
|
131
|
+
return unless Dir.exist?(Constants::SHARED_DIR)
|
|
132
|
+
|
|
133
|
+
Dir.glob(File.join(Constants::SHARED_DIR, '**', '*')).each do |src|
|
|
134
|
+
next unless File.file?(src)
|
|
135
|
+
|
|
136
|
+
rel = src.sub(%r{\A#{Regexp.escape(Constants::SHARED_DIR)}/}, '')
|
|
137
|
+
dest = File.join(target_dir, rel)
|
|
138
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
|
139
|
+
File.write(dest, File.read(src))
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
102
143
|
def read_template(name)
|
|
103
|
-
path = File.join(HOOKS_DIR, name)
|
|
144
|
+
path = File.join(Constants::HOOKS_DIR, name)
|
|
104
145
|
File.read(path)
|
|
105
146
|
end
|
|
106
147
|
|
data/lib/rails_git_hooks.rb
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Git commit-msg hook: prepends [TICKET] when branch contains a Jira-style ticket.
|
|
6
|
+
# Logic in templates/shared/commit_msg/.
|
|
7
|
+
|
|
8
|
+
# Bootstrap: resolve .git dir and skip if hook is disabled
|
|
9
|
+
repo_root = Dir.pwd
|
|
10
|
+
git_dir = File.join(repo_root, '.git')
|
|
11
|
+
git_dir = File.expand_path(File.read(git_dir).strip.sub(/\Agitdir: \s*/, ''), repo_root) if File.file?(git_dir)
|
|
12
|
+
disabled_file = File.join(git_dir, 'rails_git_hooks_disabled')
|
|
13
|
+
if File.exist?(disabled_file)
|
|
14
|
+
disabled = File.read(disabled_file).split("\n").map(&:strip)
|
|
15
|
+
exit 0 if disabled.include?('*') || disabled.include?('commit-msg')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module RailsGitHooks
|
|
19
|
+
end
|
|
20
|
+
RailsGitHooks.const_set(:GIT_DIR, git_dir.freeze)
|
|
21
|
+
hooks_dir = File.dirname(File.expand_path(__FILE__))
|
|
22
|
+
|
|
23
|
+
load File.join(hooks_dir, 'commit_msg', 'jira_prefix.rb')
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Blocks commits on default branch (master/main). Warns on debugger statements (Ruby/JS/TS/Python).
|
|
6
|
+
# Optionally runs RuboCop and whitespace/conflict checks.
|
|
7
|
+
# Logic is in templates/shared/pre_commit/ for easier maintenance and adding new checks.
|
|
8
|
+
|
|
9
|
+
# Bootstrap: resolve .git dir and skip if hook is disabled
|
|
10
|
+
repo_root = Dir.pwd
|
|
11
|
+
git_dir = File.join(repo_root, '.git')
|
|
12
|
+
git_dir = File.expand_path(File.read(git_dir).strip.sub(/\Agitdir: \s*/, ''), repo_root) if File.file?(git_dir)
|
|
13
|
+
disabled_file = File.join(git_dir, 'rails_git_hooks_disabled')
|
|
14
|
+
if File.exist?(disabled_file)
|
|
15
|
+
disabled = File.read(disabled_file).split("\n").map(&:strip)
|
|
16
|
+
exit 0 if disabled.include?('*') || disabled.include?('pre-commit')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module RailsGitHooks
|
|
20
|
+
end
|
|
21
|
+
RailsGitHooks.const_set(:GIT_DIR, git_dir.freeze)
|
|
22
|
+
hooks_dir = File.dirname(File.expand_path(__FILE__))
|
|
23
|
+
|
|
24
|
+
load File.join(hooks_dir, 'pre_commit', 'whitespace_check.rb')
|
|
25
|
+
load File.join(hooks_dir, 'pre_commit', 'default_branch.rb')
|
|
26
|
+
load File.join(hooks_dir, 'pre_commit', 'debugger_check.rb')
|
|
27
|
+
load File.join(hooks_dir, 'pre_commit', 'rubocop_check.rb')
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
#
|
|
5
5
|
# Runs the full test suite before push. Push is aborted if tests fail.
|
|
6
|
-
#
|
|
6
|
+
# Logic in templates/shared/pre_push/.
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Bootstrap: resolve .git dir and skip if hook is disabled
|
|
9
9
|
repo_root = Dir.pwd
|
|
10
10
|
git_dir = File.join(repo_root, '.git')
|
|
11
11
|
git_dir = File.expand_path(File.read(git_dir).strip.sub(/\Agitdir: \s*/, ''), repo_root) if File.file?(git_dir)
|
|
@@ -15,7 +15,9 @@ if File.exist?(disabled_file)
|
|
|
15
15
|
exit 0 if disabled.include?('*') || disabled.include?('pre-push')
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
module RailsGitHooks
|
|
19
|
+
end
|
|
20
|
+
RailsGitHooks.const_set(:GIT_DIR, git_dir.freeze)
|
|
21
|
+
hooks_dir = File.dirname(File.expand_path(__FILE__))
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
exit $CHILD_STATUS.to_s[-1].to_i
|
|
23
|
+
load File.join(hooks_dir, 'pre_push', 'run_tests.rb')
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Prepends [TICKET] to commit message when branch name contains a Jira-style ticket.
|
|
4
|
+
# No config needed; works with any project key (2–5 letters + digits).
|
|
5
|
+
|
|
6
|
+
commit_message_file = ARGV[0]
|
|
7
|
+
branch_name = `git branch --no-color 2> /dev/null`[/^\* (.+)/, 1].to_s
|
|
8
|
+
original_commit_message = File.read(commit_message_file).strip
|
|
9
|
+
|
|
10
|
+
branch_ticket_pattern = /([A-Z]{2,5}-\d+)/i
|
|
11
|
+
skip_if_already_prefixed = /\A\[[A-Z]{2,5}-\d+\]/i
|
|
12
|
+
|
|
13
|
+
if (m = branch_name.match(branch_ticket_pattern))
|
|
14
|
+
jira_ticket = m.captures.first
|
|
15
|
+
|
|
16
|
+
unless original_commit_message.match?(skip_if_already_prefixed) || original_commit_message.include?(jira_ticket)
|
|
17
|
+
message = "[#{jira_ticket}] #{original_commit_message}"
|
|
18
|
+
File.open(commit_message_file, 'w') { |f| f.write message }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Warns when staged files contain debugger statements (Ruby, JavaScript/TypeScript, Python).
|
|
4
|
+
# Does not block the commit. Expects RailsGitHooks::GIT_DIR to be set by the loader.
|
|
5
|
+
|
|
6
|
+
# [ extension => [ [ regex, label ], ... ] ]
|
|
7
|
+
DEBUGGER_PATTERNS = {
|
|
8
|
+
'.rb' => [
|
|
9
|
+
[/\bbinding\.pry\b/, 'binding.pry'],
|
|
10
|
+
[/\bbinding\.irb\b/, 'binding.irb'],
|
|
11
|
+
[/\bdebugger\b/, 'debugger'],
|
|
12
|
+
[/\bbyebug\b/, 'byebug']
|
|
13
|
+
],
|
|
14
|
+
'.js' => [[/\bdebugger\s*;?/, 'debugger']],
|
|
15
|
+
'.jsx' => [[/\bdebugger\s*;?/, 'debugger']],
|
|
16
|
+
'.ts' => [[/\bdebugger\s*;?/, 'debugger']],
|
|
17
|
+
'.tsx' => [[/\bdebugger\s*;?/, 'debugger']],
|
|
18
|
+
'.mjs' => [[/\bdebugger\s*;?/, 'debugger']],
|
|
19
|
+
'.cjs' => [[/\bdebugger\s*;?/, 'debugger']],
|
|
20
|
+
'.py' => [
|
|
21
|
+
[/\bbreakpoint\s*\(\s*\)/, 'breakpoint()'],
|
|
22
|
+
[/\bpdb\.set_trace\s*\(\s*\)/, 'pdb.set_trace()'],
|
|
23
|
+
[/\bipdb\.set_trace\s*\(\s*\)/, 'ipdb.set_trace()']
|
|
24
|
+
]
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
staged = `git diff --cached --name-only`.split("\n").map(&:strip).reject(&:empty?)
|
|
28
|
+
warnings = []
|
|
29
|
+
|
|
30
|
+
staged.each do |path|
|
|
31
|
+
next unless File.file?(path)
|
|
32
|
+
|
|
33
|
+
ext = File.extname(path)
|
|
34
|
+
patterns = DEBUGGER_PATTERNS[ext]
|
|
35
|
+
next unless patterns
|
|
36
|
+
|
|
37
|
+
File.read(path).lines.each_with_index do |line, i|
|
|
38
|
+
patterns.each do |regex, label|
|
|
39
|
+
warnings << "#{path}:#{i + 1}: #{label}" if line.match?(regex)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
unless warnings.empty?
|
|
45
|
+
warn 'Warning (debugger check):'
|
|
46
|
+
warnings.uniq.each { |e| warn " #{e}" }
|
|
47
|
+
end
|
|
48
|
+
# Does not exit 1 — commit is never blocked by this check
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Prevent commits on default branch (master/main).
|
|
4
|
+
|
|
5
|
+
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
|
6
|
+
if %w[master main].include?(branch)
|
|
7
|
+
warn "Commits on '#{branch}' are not allowed. Create a feature branch."
|
|
8
|
+
exit 1
|
|
9
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# RuboCop on staged .rb files (off by default; enable with rails_git_hooks enable rubocop-check).
|
|
4
|
+
# Expects RailsGitHooks::GIT_DIR to be set by the loader.
|
|
5
|
+
|
|
6
|
+
git_dir = RailsGitHooks::GIT_DIR
|
|
7
|
+
rubocop_check_file = File.join(git_dir, 'rails_git_hooks_rubocop')
|
|
8
|
+
if File.exist?(rubocop_check_file)
|
|
9
|
+
require 'english'
|
|
10
|
+
require 'rubocop'
|
|
11
|
+
|
|
12
|
+
ADDED_OR_MODIFIED = /A|AM|^M/.freeze
|
|
13
|
+
|
|
14
|
+
changed_files = `git status --porcelain`.split(/\n/)
|
|
15
|
+
.select { |file_name_with_status| file_name_with_status =~ ADDED_OR_MODIFIED }
|
|
16
|
+
.map { |file_name_with_status| file_name_with_status.split(' ')[1] }
|
|
17
|
+
.select { |file_name| File.extname(file_name) == '.rb' }
|
|
18
|
+
.join(' ')
|
|
19
|
+
|
|
20
|
+
unless changed_files.empty?
|
|
21
|
+
system("rubocop #{changed_files}")
|
|
22
|
+
exit $CHILD_STATUS.to_s[-1].to_i
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Trailing whitespace / conflict markers (off by default; enable with rails_git_hooks enable whitespace-check).
|
|
4
|
+
# Expects RailsGitHooks::GIT_DIR to be set by the loader.
|
|
5
|
+
|
|
6
|
+
git_dir = RailsGitHooks::GIT_DIR
|
|
7
|
+
whitespace_check_file = File.join(git_dir, 'rails_git_hooks_whitespace_check')
|
|
8
|
+
if File.exist?(whitespace_check_file)
|
|
9
|
+
staged = `git diff --cached --name-only`.split("\n").map(&:strip).reject(&:empty?)
|
|
10
|
+
errors = []
|
|
11
|
+
staged.each do |path|
|
|
12
|
+
next unless File.file?(path)
|
|
13
|
+
|
|
14
|
+
File.read(path).lines.each_with_index do |line, i|
|
|
15
|
+
errors << "#{path}:#{i + 1}: trailing whitespace" if line.match?(/[ \t]\z/)
|
|
16
|
+
stripped = line.strip
|
|
17
|
+
errors << "#{path}:#{i + 1}: conflict marker" if stripped.start_with?('<<<<<<<', '=======', '>>>>>>>')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
unless errors.empty?
|
|
21
|
+
warn 'Commit rejected (whitespace/conflict check):'
|
|
22
|
+
errors.uniq.each { |e| warn " #{e}" }
|
|
23
|
+
exit 1
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Runs the full test suite before push; aborts push if tests fail.
|
|
4
|
+
# Uses bundle exec rspec. For Minitest, edit to use bundle exec rake test.
|
|
5
|
+
|
|
6
|
+
require 'english'
|
|
7
|
+
|
|
8
|
+
system('bundle exec rspec')
|
|
9
|
+
exit $CHILD_STATUS.to_s[-1].to_i
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_git_hooks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nikita Nazarov
|
|
@@ -65,11 +65,18 @@ files:
|
|
|
65
65
|
- bin/rails_git_hooks
|
|
66
66
|
- lib/rails_git_hooks.rb
|
|
67
67
|
- lib/rails_git_hooks/cli.rb
|
|
68
|
+
- lib/rails_git_hooks/constants.rb
|
|
68
69
|
- lib/rails_git_hooks/installer.rb
|
|
69
|
-
- lib/rails_git_hooks/templates/commit-msg
|
|
70
|
-
- lib/rails_git_hooks/templates/pre-commit
|
|
71
|
-
- lib/rails_git_hooks/templates/pre-push
|
|
72
70
|
- lib/rails_git_hooks/version.rb
|
|
71
|
+
- templates/hooks/commit-msg
|
|
72
|
+
- templates/hooks/pre-commit
|
|
73
|
+
- templates/hooks/pre-push
|
|
74
|
+
- templates/shared/commit_msg/jira_prefix.rb
|
|
75
|
+
- templates/shared/pre_commit/debugger_check.rb
|
|
76
|
+
- templates/shared/pre_commit/default_branch.rb
|
|
77
|
+
- templates/shared/pre_commit/rubocop_check.rb
|
|
78
|
+
- templates/shared/pre_commit/whitespace_check.rb
|
|
79
|
+
- templates/shared/pre_push/run_tests.rb
|
|
73
80
|
homepage: https://github.com/NikitaNazarov1/rails_git_hooks
|
|
74
81
|
licenses:
|
|
75
82
|
- MIT
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
# Git commit-msg hook: if branch name contains a Jira ticket (e.g. APD-1234),
|
|
6
|
-
# prepends "[APD-1234] " to commit messages unless already present.
|
|
7
|
-
# JIRA_PROJECT_KEY is replaced at install time by git_hooks; for manual install, replace it with your project key.
|
|
8
|
-
|
|
9
|
-
# Git runs hooks with CWD = repo root; find .git from here
|
|
10
|
-
repo_root = Dir.pwd
|
|
11
|
-
git_dir = File.join(repo_root, '.git')
|
|
12
|
-
git_dir = File.expand_path(File.read(git_dir).strip.sub(/\Agitdir: \s*/, ''), repo_root) if File.file?(git_dir)
|
|
13
|
-
disabled_file = File.join(git_dir, 'rails_git_hooks_disabled')
|
|
14
|
-
if File.exist?(disabled_file)
|
|
15
|
-
disabled = File.read(disabled_file).split("\n").map(&:strip)
|
|
16
|
-
exit 0 if disabled.include?('*') || disabled.include?('commit-msg')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
commit_message_file = ARGV[0]
|
|
20
|
-
branch_name = `git branch --no-color 2> /dev/null`[/^\* (.+)/, 1].to_s
|
|
21
|
-
original_commit_message = File.read(commit_message_file).strip
|
|
22
|
-
|
|
23
|
-
pattern = /(JIRA_PROJECT_KEY-\d+)/i
|
|
24
|
-
|
|
25
|
-
if (m = branch_name.match(pattern))
|
|
26
|
-
jira_number = m.captures.first
|
|
27
|
-
|
|
28
|
-
exit 0 if original_commit_message.include?(jira_number)
|
|
29
|
-
|
|
30
|
-
message = "[#{jira_number}] #{original_commit_message}"
|
|
31
|
-
File.open(commit_message_file, 'w') { |f| f.write message }
|
|
32
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
# Runs RuboCop on staged .rb files. Commit is aborted if RuboCop reports offenses.
|
|
6
|
-
|
|
7
|
-
# Git runs hooks with CWD = repo root; find .git from here
|
|
8
|
-
repo_root = Dir.pwd
|
|
9
|
-
git_dir = File.join(repo_root, '.git')
|
|
10
|
-
git_dir = File.expand_path(File.read(git_dir).strip.sub(/\Agitdir: \s*/, ''), repo_root) if File.file?(git_dir)
|
|
11
|
-
disabled_file = File.join(git_dir, 'rails_git_hooks_disabled')
|
|
12
|
-
if File.exist?(disabled_file)
|
|
13
|
-
disabled = File.read(disabled_file).split("\n").map(&:strip)
|
|
14
|
-
exit 0 if disabled.include?('*') || disabled.include?('pre-commit')
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Trailing whitespace / conflict markers check (disabled by default; enable with .git/rails_git_hooks_whitespace_check)
|
|
18
|
-
whitespace_check_file = File.join(git_dir, 'rails_git_hooks_whitespace_check')
|
|
19
|
-
if File.exist?(whitespace_check_file)
|
|
20
|
-
staged = `git diff --cached --name-only`.split("\n").map(&:strip).reject(&:empty?)
|
|
21
|
-
errors = []
|
|
22
|
-
staged.each do |path|
|
|
23
|
-
next unless File.file?(path)
|
|
24
|
-
|
|
25
|
-
File.read(path).lines.each_with_index do |line, i|
|
|
26
|
-
errors << "#{path}:#{i + 1}: trailing whitespace" if line.match?(/[ \t]\z/)
|
|
27
|
-
stripped = line.strip
|
|
28
|
-
errors << "#{path}:#{i + 1}: conflict marker" if stripped.start_with?('<<<<<<<', '=======', '>>>>>>>')
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
unless errors.empty?
|
|
32
|
-
warn 'Commit rejected (whitespace/conflict check):'
|
|
33
|
-
errors.uniq.each { |e| warn " #{e}" }
|
|
34
|
-
exit 1
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Prevent commits on default branch (master/main)
|
|
39
|
-
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
|
40
|
-
if %w[master main].include?(branch)
|
|
41
|
-
warn "Commits on '#{branch}' are not allowed. Create a feature branch."
|
|
42
|
-
exit 1
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
require 'english'
|
|
46
|
-
require 'rubocop'
|
|
47
|
-
|
|
48
|
-
ADDED_OR_MODIFIED = /A|AM|^M/.freeze
|
|
49
|
-
|
|
50
|
-
changed_files = `git status --porcelain`.split(/\n/)
|
|
51
|
-
.select { |file_name_with_status| file_name_with_status =~ ADDED_OR_MODIFIED }
|
|
52
|
-
.map { |file_name_with_status| file_name_with_status.split(' ')[1] }
|
|
53
|
-
.select { |file_name| File.extname(file_name) == '.rb' }
|
|
54
|
-
.join(' ')
|
|
55
|
-
|
|
56
|
-
system("rubocop #{changed_files}") unless changed_files.empty?
|
|
57
|
-
|
|
58
|
-
exit $CHILD_STATUS.to_s[-1].to_i
|