git-lint 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE.adoc +162 -0
  5. data/README.adoc +1068 -0
  6. data/bin/git-lint +9 -0
  7. data/lib/git/kit/repo.rb +30 -0
  8. data/lib/git/lint.rb +51 -0
  9. data/lib/git/lint/analyzers/abstract.rb +108 -0
  10. data/lib/git/lint/analyzers/commit_author_capitalization.rb +35 -0
  11. data/lib/git/lint/analyzers/commit_author_email.rb +35 -0
  12. data/lib/git/lint/analyzers/commit_author_name.rb +40 -0
  13. data/lib/git/lint/analyzers/commit_body_bullet.rb +43 -0
  14. data/lib/git/lint/analyzers/commit_body_bullet_capitalization.rb +46 -0
  15. data/lib/git/lint/analyzers/commit_body_bullet_delimiter.rb +40 -0
  16. data/lib/git/lint/analyzers/commit_body_issue_tracker_link.rb +45 -0
  17. data/lib/git/lint/analyzers/commit_body_leading_line.rb +30 -0
  18. data/lib/git/lint/analyzers/commit_body_line_length.rb +42 -0
  19. data/lib/git/lint/analyzers/commit_body_paragraph_capitalization.rb +47 -0
  20. data/lib/git/lint/analyzers/commit_body_phrase.rb +72 -0
  21. data/lib/git/lint/analyzers/commit_body_presence.rb +36 -0
  22. data/lib/git/lint/analyzers/commit_body_single_bullet.rb +40 -0
  23. data/lib/git/lint/analyzers/commit_subject_length.rb +33 -0
  24. data/lib/git/lint/analyzers/commit_subject_prefix.rb +42 -0
  25. data/lib/git/lint/analyzers/commit_subject_suffix.rb +39 -0
  26. data/lib/git/lint/analyzers/commit_trailer_collaborator_capitalization.rb +51 -0
  27. data/lib/git/lint/analyzers/commit_trailer_collaborator_duplication.rb +56 -0
  28. data/lib/git/lint/analyzers/commit_trailer_collaborator_email.rb +52 -0
  29. data/lib/git/lint/analyzers/commit_trailer_collaborator_key.rb +56 -0
  30. data/lib/git/lint/analyzers/commit_trailer_collaborator_name.rb +57 -0
  31. data/lib/git/lint/branches/environments/circle_ci.rb +28 -0
  32. data/lib/git/lint/branches/environments/local.rb +28 -0
  33. data/lib/git/lint/branches/environments/netlify_ci.rb +34 -0
  34. data/lib/git/lint/branches/environments/travis_ci.rb +57 -0
  35. data/lib/git/lint/branches/feature.rb +44 -0
  36. data/lib/git/lint/cli.rb +122 -0
  37. data/lib/git/lint/collector.rb +64 -0
  38. data/lib/git/lint/commits/saved.rb +104 -0
  39. data/lib/git/lint/commits/unsaved.rb +120 -0
  40. data/lib/git/lint/errors/base.rb +14 -0
  41. data/lib/git/lint/errors/severity.rb +13 -0
  42. data/lib/git/lint/errors/sha.rb +13 -0
  43. data/lib/git/lint/identity.rb +13 -0
  44. data/lib/git/lint/kit/filter_list.rb +30 -0
  45. data/lib/git/lint/parsers/trailers/collaborator.rb +57 -0
  46. data/lib/git/lint/rake/setup.rb +4 -0
  47. data/lib/git/lint/rake/tasks.rb +33 -0
  48. data/lib/git/lint/refinements/strings.rb +25 -0
  49. data/lib/git/lint/reporters/branch.rb +67 -0
  50. data/lib/git/lint/reporters/commit.rb +30 -0
  51. data/lib/git/lint/reporters/line.rb +32 -0
  52. data/lib/git/lint/reporters/lines/paragraph.rb +49 -0
  53. data/lib/git/lint/reporters/lines/sentence.rb +31 -0
  54. data/lib/git/lint/reporters/style.rb +52 -0
  55. data/lib/git/lint/runner.rb +34 -0
  56. data/lib/git/lint/validators/capitalization.rb +29 -0
  57. data/lib/git/lint/validators/email.rb +24 -0
  58. data/lib/git/lint/validators/name.rb +30 -0
  59. metadata +363 -0
  60. metadata.gz.sig +3 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4ea240069467c66adef23372741330ebd90180d3099cceb9c096ae9575eb4475
4
+ data.tar.gz: 8bec2e0c1d7348ee5af25a11641c8bd02d3773c055151c52252a69d5c2706daf
5
+ SHA512:
6
+ metadata.gz: 33c49480b58f1e6b44d4246f8306b8d9ba0ce68ca4cc059fe19a403a1d08fd50370f45a917eba39dbe5bf664d1377d044c20155b86c763307bdbd725d1bb95da
7
+ data.tar.gz: 598eb09a297689e9a930c01f46062fe9587fff7df02b430d74b69c9bd59af3e876a27e855b8d04cef3b4aec4ac8738a242797894a098c0bfcf28ee4a576d16c3
Binary file
Binary file
@@ -0,0 +1,162 @@
1
+ = Apache License
2
+
3
+ Version 2.0, January 2004
4
+
5
+ http://www.apache.org/licenses
6
+
7
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
+
9
+ == 1. Definitions
10
+
11
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by
12
+ Sections 1 through 9 of this document.
13
+
14
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is
15
+ granting the License.
16
+
17
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are
18
+ controlled by, or are under common control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the direction or management of such
20
+ entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this
24
+ License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications, including but not limited to
27
+ software source code, documentation source, and configuration files.
28
+
29
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a
30
+ Source form, including but not limited to compiled object code, generated documentation, and
31
+ conversions to other media types.
32
+
33
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the
34
+ License, as indicated by a copyright notice that is included in or attached to the work (an example
35
+ is provided in the Appendix below).
36
+
37
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or
38
+ derived from) the Work and for which the editorial revisions, annotations, elaborations, or other
39
+ modifications represent, as a whole, an original work of authorship. For the purposes of this
40
+ License, Derivative Works shall not include works that remain separable from, or merely link (or
41
+ bind by name) to the interfaces of, the Work and Derivative Works thereof.
42
+
43
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any
44
+ modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted
45
+ to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity
46
+ authorized to submit on behalf of the copyright owner. For the purposes of this definition,
47
+ "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or
48
+ its representatives, including but not limited to communication on electronic mailing lists, source
49
+ code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor
50
+ for the purpose of discussing and improving the Work, but excluding communication that is
51
+ conspicuously marked or otherwise designated in writing by the copyright owner as "Not a
52
+ Contribution."
53
+
54
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a
55
+ Contribution has been received by Licensor and subsequently incorporated within the Work.
56
+
57
+ == 2. Grant of Copyright License
58
+
59
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a
60
+ perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to
61
+ reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and
62
+ distribute the Work and such Derivative Works in Source or Object form.
63
+
64
+ == 3. Grant of Patent License
65
+
66
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a
67
+ perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
68
+ section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer
69
+ the Work, where such license applies only to those patent claims licensable by such Contributor that
70
+ are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s)
71
+ with the Work to which such Contribution(s) was submitted. If You institute patent litigation
72
+ against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or
73
+ a Contribution incorporated within the Work constitutes direct or contributory patent infringement,
74
+ then any patent licenses granted to You under this License for that Work shall terminate as of the
75
+ date such litigation is filed.
76
+
77
+ == 4. Redistribution
78
+
79
+ You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with
80
+ or without modifications, and in Source or Object form, provided that You meet the following
81
+ conditions:
82
+
83
+ . You must give any other recipients of the Work or Derivative Works a copy of this License; and
84
+
85
+ . You must cause any modified files to carry prominent notices stating that You changed the files;
86
+ and
87
+
88
+ . You must retain, in the Source form of any Derivative Works that You distribute, all copyright,
89
+ patent, trademark, and attribution notices from the Source form of the Work, excluding those
90
+ notices that do not pertain to any part of the Derivative Works; and
91
+
92
+ . If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works
93
+ that You distribute must include a readable copy of the attribution notices contained within such
94
+ NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in
95
+ at least one of the following places: within a NOTICE text file distributed as part of the
96
+ Derivative Works; within the Source form or documentation, if provided along with the Derivative
97
+ Works; or, within a display generated by the Derivative Works, if and wherever such third-party
98
+ notices normally appear. The contents of the NOTICE file are for informational purposes only and
99
+ do not modify the License. You may add Your own attribution notices within Derivative Works that
100
+ You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such
101
+ additional attribution notices cannot be construed as modifying the License.
102
+
103
+ You may add Your own copyright statement to Your modifications and may provide additional or
104
+ different license terms and conditions for use, reproduction, or distribution of Your modifications,
105
+ or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of
106
+ the Work otherwise complies with the conditions stated in this License.
107
+
108
+ == 5. Submission of Contributions
109
+
110
+ Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the
111
+ Work by You to the Licensor shall be under the terms and conditions of this License, without any
112
+ additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify
113
+ the terms of any separate license agreement you may have executed with Licensor regarding such
114
+ Contributions.
115
+
116
+ == 6. Trademarks
117
+
118
+ This License does not grant permission to use the trade names, trademarks, service marks, or product
119
+ names of the Licensor, except as required for reasonable and customary use in describing the origin
120
+ of the Work and reproducing the content of the NOTICE file.
121
+
122
+ == 7. Disclaimer of Warranty
123
+
124
+ Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each
125
+ Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
126
+ KIND, either express or implied, including, without limitation, any warranties or conditions of
127
+ TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely
128
+ responsible for determining the appropriateness of using or redistributing the Work and assume any
129
+ risks associated with Your exercise of permissions under this License.
130
+
131
+ == 8. Limitation of Liability
132
+
133
+ In no event and under no legal theory, whether in tort (including negligence), contract, or
134
+ otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or
135
+ agreed to in writing, shall any Contributor be liable to You for damages, including any direct,
136
+ indirect, special, incidental, or consequential damages of any character arising as a result of this
137
+ License or out of the use or inability to use the Work (including but not limited to damages for
138
+ loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial
139
+ damages or losses), even if such Contributor has been advised of the possibility of such damages.
140
+
141
+ == 9. Accepting Warranty or Additional Liability
142
+
143
+ While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee
144
+ for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights
145
+ consistent with this License. However, in accepting such obligations, You may act only on Your own
146
+ behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You
147
+ agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or
148
+ claims asserted against, such Contributor by reason of your accepting any such warranty or
149
+ additional liability.
150
+
151
+ END OF TERMS AND CONDITIONS
152
+
153
+ Copyright link:https://www.alchemists.io[Alchemists].
154
+
155
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
156
+ compliance with the License. You may obtain a link:https://www.apache.org/licenses/LICENSE-2.0[copy]
157
+ of the License.
158
+
159
+ Unless required by applicable law or agreed to in writing, software distributed under the License is
160
+ distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
161
+ implied. See the License for the specific language governing permissions and limitations under the
162
+ License.
@@ -0,0 +1,1068 @@
1
+ :toc: macro
2
+ :toclevels: 5
3
+ :figure-caption!:
4
+
5
+ :git_rebase_workflow_link: link:https://www.alchemists.io/articles/git_commit_anatomy[Git Rebase Workflow]
6
+
7
+ = Git Lint
8
+
9
+ [link=http://badge.fury.io/rb/git-lint]
10
+ image::https://badge.fury.io/rb/git-lint.svg[Gem Version]
11
+ [link=https://circleci.com/gh/bkuhlmann/git-lint]
12
+ image::https://circleci.com/gh/bkuhlmann/git-lint.svg?style=svg[Circle CI Status]
13
+
14
+ [link=https://travis-ci.org/bkuhlmann/git-lint]
15
+ image::https://travis-ci.org/bkuhlmann/git-lint.svg?branch=master[Travis CI Status]
16
+ [link=https://app.netlify.com/sites/git-lint/deploys]
17
+ image::https://api.netlify.com/api/v1/badges/d4a15c9c-46ba-49db-9f31-33f389ee3259/deploy-status[Netlify CI Status]
18
+
19
+ A command line interface for linting Git commits. Ensures you maintain a clean, easy to read,
20
+ debuggable, and maintainable project history.
21
+
22
+ *Git Lint is the offical port of the original Git Cop project that avoids references to violence or
23
+ violent terminology that might make anyone feel unwelcome. The name change was necessary in order to
24
+ better support the link:https://blacklivesmatter.com[Black Lives Matter] and
25
+ link:https://8cantwait.org[Defund Police] movements.*
26
+
27
+ toc::[]
28
+
29
+ == Features
30
+
31
+ * Enforces a {git_rebase_workflow_link}.
32
+ * Enforces a clean and consistent Git commit history.
33
+ * Provides a customizable suite of analyzers.
34
+ * Provides Git Hook support for local use.
35
+ * Provides Continuous Integration (CI) build server support.
36
+
37
+ == Screencasts
38
+
39
+ [link=https://www.alchemists.io/screencasts/git_lint]
40
+ image::https://www.alchemists.io/images/screencasts/git_lint/cover-original.png[Screencast,role=focal_point]
41
+
42
+ == Requirements
43
+
44
+ . link:https://www.ruby-lang.org[Ruby 2.7.0] (or higher)
45
+
46
+ == Setup
47
+
48
+ === Production
49
+
50
+ To install, run:
51
+
52
+ [source,bash]
53
+ ----
54
+ gem install git-lint
55
+ ----
56
+
57
+ === Development
58
+
59
+ To contribute, run:
60
+
61
+ [source,bash]
62
+ ----
63
+ git clone https://github.com/bkuhlmann/git-lint.git
64
+ cd git-lint
65
+ bin/setup
66
+ ----
67
+
68
+ You can also use the IRB console for direct access to all objects:
69
+
70
+ [source,bash]
71
+ ----
72
+ bin/console
73
+ ----
74
+
75
+ == Usage
76
+
77
+ === Command Line Interface (CLI)
78
+
79
+ From the command line, type: `git-lint --help`
80
+
81
+ ....
82
+ git-lint --hook # Add Git Hook support.
83
+ git-lint -a, [--analyze] # Analyze feature branch for issues.
84
+ git-lint -c, [--config] # Manage gem configuration.
85
+ git-lint -h, [--help=COMMAND] # Show this message or get help for a command.
86
+ git-lint -v, [--version] # Show gem version.
87
+ ....
88
+
89
+ To check if your Git commit history is clean, run: `git-lint --analyze`. It will exit with a failure
90
+ if at least one issue with error severity is detected.
91
+
92
+ This gem does not check commits on `master`. This is intentional as you would, generally, not want
93
+ to rewrite or fix commits on `master`. This gem is best used on feature branches as it automatically
94
+ detects all commits made since `master` on the feature branch.
95
+
96
+ Here is an example workflow, using gem defaults with issues detected:
97
+
98
+ [source,bash]
99
+ ----
100
+ cd example
101
+ git checkout -b test
102
+ touch text.txt
103
+ git add --all .
104
+ git commit --message "This is a bogus commit message that is also terribly long and will word wrap"
105
+ git-lint --analyze
106
+ ----
107
+
108
+ Output:
109
+
110
+ ....
111
+ Running Git Lint...
112
+
113
+ 83dbad531d84a184e55cbb38c5b2a4e5fa5bcaee (Brooke Kuhlmann, 0 seconds ago): This is a bogus commit message that is also terribly long and will word wrap.
114
+ Commit Body Presence Warning. Use minimum of 1 line (non-empty).
115
+ Commit Subject Length Error. Use 72 characters or less.
116
+ Commit Subject Prefix Error. Use: /Fixed/, /Added/, /Updated/, /Removed/, /Refactored/.
117
+ Commit Subject Suffix Error. Avoid: /\./, /\?/, /\!/.
118
+
119
+ 1 commit inspected. 4 issues detected (1 warning, 3 errors).
120
+ ....
121
+
122
+ === Rake
123
+
124
+ This gem provides optional Rake tasks. They can be added to your project by adding the following
125
+ requirement to the top of your `Rakefile`:
126
+
127
+ [source,ruby]
128
+ ----
129
+ require "git/lint/rake/setup"
130
+ ----
131
+
132
+ Now, when running `bundle exec rake -T`, you'll see `git_lint` included in the list.
133
+
134
+ If you need a concrete example, check out the link:Rakefile[Rakefile] of this project for details.
135
+
136
+ === Configuration
137
+
138
+ This gem can be configured via a global configuration:
139
+
140
+ ....
141
+ $HOME/.config/git-lint/configuration.yml
142
+ ....
143
+
144
+ It can also be configured via link:https://www.alchemists.io/projects/xdg[XDG] environment
145
+ variables. The default configuration is:
146
+
147
+ [source,yaml]
148
+ ----
149
+ :commit_author_capitalization:
150
+ :enabled: true
151
+ :severity: :error
152
+ :commit_author_email:
153
+ :enabled: true
154
+ :severity: :error
155
+ :commit_author_name:
156
+ :enabled: true
157
+ :severity: :error
158
+ :minimum: 2
159
+ :commit_body_bullet:
160
+ :enabled: true
161
+ :severity: :error
162
+ :excludes:
163
+ - "\\*"
164
+ - "â€ĸ"
165
+ :commit_body_bullet_capitalization:
166
+ :enabled: true
167
+ :severity: :error
168
+ :includes: "\\-"
169
+ :commit_body_bullet_delimiter:
170
+ :enabled: true
171
+ :severity: :error
172
+ :includes: "\\-"
173
+ :commit_body_issue_tracker_link:
174
+ :enabled: true,
175
+ :severity: :error
176
+ :excludes:
177
+ - "(f|F)ix(es|ed)?\\s\\#\\d+"
178
+ - "(c|C)lose(s|d)?\\s\\#\\d+"
179
+ - "(r|R)esolve(s|d)?\\s\\#\\d+"
180
+ - "github\\.com\\/.+\\/issues\\/\\d+"
181
+ :commit_body_leading_line:
182
+ :enabled: false
183
+ :severity: :warn
184
+ :commit_body_line_length:
185
+ :enabled: true
186
+ :severity: :error
187
+ :length: 72
188
+ :commit_body_paragraph_capitalization:
189
+ :enabled: true
190
+ :severity: :error
191
+ :commit_body_phrase:
192
+ :enabled: true
193
+ :severity: :error
194
+ :excludes:
195
+ - "absolutely"
196
+ - "actually"
197
+ - "all intents and purposes"
198
+ - "along the lines"
199
+ - "at this moment in time"
200
+ - "basically"
201
+ - "each and every one"
202
+ - "everyone knows"
203
+ - "fact of the matter"
204
+ - "furthermore"
205
+ - "however"
206
+ - "in due course"
207
+ - "in the end"
208
+ - "last but not least"
209
+ - "matter of fact"
210
+ - "obviously"
211
+ - "of course"
212
+ - "really"
213
+ - "simply"
214
+ - "things being equal"
215
+ - "would like to"
216
+ - "/\\beasy\\b/"
217
+ - "/\\bjust\\b/"
218
+ - "/\\bquite\\b/"
219
+ - "/as\\sfar\\sas\\s.+\\sconcerned/"
220
+ - "/of\\sthe\\s(fact|opinion)\\sthat/"
221
+ :commit_body_presence:
222
+ :enabled: false
223
+ :severity: :warn
224
+ :minimum: 1
225
+ :commit_body_single_bullet:
226
+ :enabled: true
227
+ :severity: :error
228
+ :includes: "\\-"
229
+ :commit_subject_length:
230
+ :enabled: true
231
+ :severity: :error
232
+ :length: 72
233
+ :commit_subject_prefix:
234
+ :enabled: true
235
+ :severity: :error
236
+ :includes:
237
+ - Fixed
238
+ - Added
239
+ - Updated
240
+ - Removed
241
+ - Refactored
242
+ :commit_subject_suffix:
243
+ :enabled: true
244
+ :severity: :error
245
+ :excludes:
246
+ - "\\."
247
+ - "\\?"
248
+ - "\\!"
249
+ :commit_trailer_collaborator_capitalization:
250
+ :enabled: true
251
+ :severity: :error
252
+ :commit_trailer_collaborator_duplication:
253
+ :enabled: true
254
+ :severity: :error
255
+ :commit_trailer_collaborator_email:
256
+ :enabled: true
257
+ :severity: :error
258
+ :commit_trailer_collaborator_key:
259
+ :enabled: true
260
+ :severity: :error
261
+ :includes:
262
+ - "Co-Authored-By"
263
+ :commit_trailer_collaborator_name:
264
+ :enabled: true
265
+ :severity: :error
266
+ :minimum: 2
267
+ ----
268
+
269
+ Feel free to take this default configuration, modify, and save as your own custom
270
+ `configuration.yml`.
271
+
272
+ === Enablement
273
+
274
+ By default, most analyzers are enabled. Accepted values are `true` or `false`. If you wish to
275
+ disable a analyzer, set it to `false`.
276
+
277
+ ==== Severity Levels
278
+
279
+ By default, most analyzers are set to `error` severity. If you wish to reduce the severity level of
280
+ a analyzer, you can set it to `warn` instead. Here are the accepted values and what each means:
281
+
282
+ * `warn`: Will count as an issue and display a warning but will not cause the program/build to
283
+ fail. Use this if you want to display issues as reminders or cautionary warnings.
284
+ * `error`: Will count as an issue, display error output, and cause the program/build to fail. Use
285
+ this setting if you want to ensure bad commits are prevented.
286
+
287
+ ==== Regular Expressions
288
+
289
+ Some analyzers support _include_ or _exclude_ lists. These lists can consist of strings, regular
290
+ expressions, or a combination thereof. Regardless of your choice, all lists are automatically
291
+ converted to regular expression for use by the analyzers. This means a string like `"example"`
292
+ becomes `/example/` and a regular expression of `"\\AExample.+"` becomes `/\AExample.+/`.
293
+
294
+ If you need help constructing complex regular expressions for these lists, try launching an IRB
295
+ session and using `Regexp.new` or `Regexp.escape` to experiment with the types of words/phrases you
296
+ want to turn into regular expressions. _For purposes of the YAML configuration, these need to be
297
+ expressed as strings with special characters escaped properly for internal conversion to a regular
298
+ expression._
299
+
300
+ === Git Hooks
301
+
302
+ This gem supports link:https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks[Git Hooks].
303
+
304
+ It is _highly recommended_ you manage Git Hooks as global scripts as it'll reduce project
305
+ maintenance costs for you. To configure global Git Hooks, add the following to your
306
+ `$HOME/.gitconfig`:
307
+
308
+ ....
309
+ [core]
310
+ hooksPath = ~/.git_template/hooks
311
+ ....
312
+
313
+ Then you can customize Git Hooks for all of your projects.
314
+ link:https://github.com/bkuhlmann/dotfiles/tree/master/home_files/.config/git/hooks[Check out these
315
+ examples].
316
+
317
+ If a global configuration is not desired, you can add Git Hooks at a per project level by editing
318
+ any of the scripts within the `.git/hooks` directory of the repository.
319
+
320
+ ==== Commit Message
321
+
322
+ The _commit-msg_ hook, which is the best way to use this gem as a Git Hook, is provided as a
323
+ `--hook` option. Run `git-lint --help --hook` for usage:
324
+
325
+ Usage:
326
+ git-lint --hook
327
+
328
+ Options:
329
+ [--commit-message=PATH] # Check commit message.
330
+
331
+ Add Git Hook support.
332
+
333
+ As shown above, the `--commit-message` option accepts a file path (i.e. `.git/COMMIT_EDITMSG`) which
334
+ is provided to you by Git within the `.git/hooks/commit-msg` script. Here is a working example of
335
+ what that script might look like:
336
+
337
+ [source,bash]
338
+ ----
339
+ #! /usr/bin/env bash
340
+
341
+ set -o nounset
342
+ set -o errexit
343
+ set -o pipefail
344
+ IFS=$'\n\t'
345
+
346
+ if ! command -v git-lint > /dev/null; then
347
+ printf "%s\n" "[git]: Git Lint not found. To install, run: gem install git-lint."
348
+ exit 1
349
+ fi
350
+
351
+ git-lint --hook --commit-message "${BASH_ARGV[0]}"
352
+ ----
353
+
354
+ Whenever you attempt to add a commit, Git Lint will check your commit for issues prior to saving it.
355
+
356
+ ==== Post Commit
357
+
358
+ The _post-commit_ hook is possible via the `--analyze --commits` option. Usage:
359
+
360
+ ....
361
+ Usage:
362
+ git-lint -a, [--analyze]
363
+
364
+ Options:
365
+ -c, [--commits=one two three] # Analyze specific commit SHA(s).
366
+
367
+ Analyze feature branch for issues.
368
+ ....
369
+
370
+ The _post-commit_ hook can be used multiple ways but, if you want it to check each commit after it
371
+ has been made, here is a working example which can be used as a `.git/hooks/post-commit` script:
372
+
373
+ [source,bash]
374
+ ----
375
+ #! /usr/bin/env bash
376
+
377
+ set -o nounset
378
+ set -o errexit
379
+ set -o pipefail
380
+ IFS=$'\n\t'
381
+
382
+ if ! command -v git-lint > /dev/null; then
383
+ printf "%s\n" "[git]: Git Lint not found. To install, run: gem install git-lint."
384
+ exit 1
385
+ fi
386
+
387
+ git-lint --analyze --commits $(git log --pretty=format:%H -1)
388
+ ----
389
+
390
+ Whenever a commit has been saved, this script will run Git Lint to check for issues.
391
+
392
+ === Continuous Integration (CI)
393
+
394
+ This gem automatically configures itself for known CI build servers (see below for details). If you
395
+ have a build server that is not listed, please log an issue or provide an implementation with
396
+ support.
397
+
398
+ Calculation of commits is done by reviewing all commits made on the feature branch since branching
399
+ from `master`.
400
+
401
+ ==== link:https://circleci.com[Circle CI]
402
+
403
+ Detection and configuration happens automatically by checking the `CIRCLECI` environment variable.
404
+ No additional setup required!
405
+
406
+ ==== link:https://www.netlify.com[Netlify CI]
407
+
408
+ Detection and configuration happens automatically by checking the `NETLIFY` environment variable. No
409
+ additional setup required!
410
+
411
+ ==== link:https://travis-ci.org[Travis CI]
412
+
413
+ Detection and configuration happens automatically by checking the `TRAVIS` environment variable. No
414
+ additional setup required!
415
+
416
+ == Analyzers
417
+
418
+ The following details the various analyzers provided by this gem to ensure a high standard of
419
+ commits for your project.
420
+
421
+ === Commit Author Capitalization
422
+
423
+ [options="header"]
424
+ |===
425
+ | Enabled | Severity | Defaults
426
+ | true | error | none
427
+ |===
428
+
429
+ Ensures author name is properly capitalized. Example:
430
+
431
+ ....
432
+ # Disallowed
433
+ jayne cobb
434
+ dr. simon tam
435
+
436
+ # Allowed
437
+ Jayne Cobb
438
+ Dr. Simon Tam
439
+ ....
440
+
441
+ === Commit Author Email
442
+
443
+ [options="header"]
444
+ |===
445
+ | Enabled | Severity | Defaults
446
+ | true | error | none
447
+ |===
448
+
449
+ Ensures author email address exists. Git requires an author email when you use it for the first time
450
+ too. This takes it a step further to ensure the email address loosely resembles an email address.
451
+
452
+ ....
453
+ # Disallowed
454
+ mudder_man
455
+
456
+ # Allowed
457
+ jayne@serenity.com
458
+ ....
459
+
460
+ === Commit Author Name
461
+
462
+ [options="header"]
463
+ |===
464
+ | Enabled | Severity | Defaults
465
+ | true | error | minimum: 2
466
+ |===
467
+
468
+ Ensures author name consists of, at least, a first and last name. Example:
469
+
470
+ ....
471
+ # Disallowed
472
+ Kaylee
473
+
474
+ # Allowed
475
+ Kaywinnet Lee Frye
476
+ ....
477
+
478
+ === Commit Body Bullet
479
+
480
+ [options="header"]
481
+ |===
482
+ | Enabled | Severity | Defaults
483
+ | true | error | excludes: `["\\*", "â€ĸ"]`
484
+ |===
485
+
486
+ Ensures commit message bodies use a standard Markdown syntax for bullet points. Markdown supports
487
+ the following syntax for bullets:
488
+
489
+ ....
490
+ *
491
+ -
492
+ ....
493
+
494
+ It's best to use dashes for bullet point syntax as stars are easier to read when used for
495
+ _emphasis_. This makes parsing the Markdown syntax easier when reviewing a Git commit as the syntax
496
+ used for bullet points and _emphasis_ are now, distinctly, unique.
497
+
498
+ === Commit Body Bullet Capitalization
499
+
500
+ [options="header"]
501
+ |===
502
+ | Enabled | Severity | Defaults
503
+ | true | error | includes: `["\\-"]`
504
+ |===
505
+
506
+ Ensures commit body bullet lines are capitalized. Example:
507
+
508
+ ....
509
+ # Disallowed
510
+ - an example bullet.
511
+
512
+ # Allowed
513
+ - An example bullet.
514
+ ....
515
+
516
+ === Commit Body Bullet Delimiter
517
+
518
+ [options="header"]
519
+ |===
520
+ | Enabled | Severity | Defaults
521
+ | true | error | includes: `["\\-"]`
522
+ |===
523
+
524
+ Ensures commit body bullets are delimited by a space. Example:
525
+
526
+ ....
527
+ # Disallowed
528
+ -An example bullet.
529
+
530
+ # Allowed
531
+ - An example bullet.
532
+ ....
533
+
534
+ === Commit Body Issue Tracker Link
535
+
536
+ [options="header"]
537
+ |===
538
+ | Enabled | Severity | Defaults
539
+ | true | error | excludes: (see configuration)
540
+ |===
541
+
542
+ Ensures commit body doesn't contain a link to an issue tracker. The exclude list defaults to GitHub
543
+ Issue links but can be customized for any issue tracker.
544
+
545
+ There are several reasons for excluding issue tracker links from commit bodies:
546
+
547
+ . Not all issue trackers preserve issues (meaning they can be deleted). This makes make reading
548
+ historic commits much harder to understand why the change was made when the link no longer works.
549
+ . When not connected to the internet or working on a laggy connection, it's hard to understand why
550
+ a commit was made when all you have is a link to an issue with no other supporting context.
551
+ . During the course of a repository's life, issue trackers can be replaced (rare but it does
552
+ happen). If the old issue tracker service is no longer paid for, none of the links within the
553
+ commit will be of any relevance.
554
+ . An issue might span several commits in order to resolve it. Including a link in each commit is
555
+ tedious and can create noise within the issue's history which is distracting.
556
+
557
+ Instead of linking to issues, take the time to write a short summary as to _why_ the commit was
558
+ made. Doing this will make it easier to understand _why_ the commit was made, keeps the commit self-
559
+ contained, and makes learning about/debugging the commit faster.
560
+
561
+ Issue tracker links are best used at the code review level due to an issue usually spanning multiple
562
+ commits in order to complete the work. When reading a code review, this is a great opportunity to
563
+ link to an issue in order to provide a high level overview and reason why the code review was
564
+ initiated in the first place.
565
+
566
+ === Commit Body Leading Line
567
+
568
+ [options="header"]
569
+ |===
570
+ | Enabled | Severity | Defaults
571
+ | true | error | none
572
+ |===
573
+
574
+ Ensures there is a leading, empty line, between the commit subject and body. Generally, this isn't
575
+ an issue but sometimes the Git CLI can be misused or a misconfigured Git editor will smash the
576
+ subject line and start of the body as one run-on paragraph. Example:
577
+
578
+ ....
579
+ # Disallowed
580
+
581
+ Curabitur eleifend wisi iaculis ipsum.
582
+ Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
583
+ quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam
584
+ egestas semper. Aenean ultricies mi vitae est. Mauris placerat's eleifend leo. Quisque et sapien
585
+ ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, orn si amt wit.
586
+
587
+ # Allowed
588
+
589
+ Curabitur eleifend wisi iaculis ipsum.
590
+
591
+ Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
592
+ quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam
593
+ egestas semper. Aenean ultricies mi vitae est. Mauris placerat's eleifend leo. Quisque et sapien
594
+ ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, orn si amt wit.
595
+ ....
596
+
597
+ === Commit Body Line Length
598
+
599
+ [options="header"]
600
+ |===
601
+ | Enabled | Severity | Defaults
602
+ | true | error | length: 72
603
+ |===
604
+
605
+ Ensures each line of the commit body is no longer than 72 characters in length for consistent
606
+ readability and word-wrap prevention on smaller screen sizes. For further details, read Tim Pope's
607
+ original link:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[article] on the
608
+ subject.
609
+
610
+ === Commit Body Paragraph Capitalization
611
+
612
+ [options="header"]
613
+ |===
614
+ | Enabled | Severity | Defaults
615
+ | true | error | none
616
+ |===
617
+
618
+ Ensures each paragraph of the commit body is capitalized. Example:
619
+
620
+ ....
621
+ # Disallowed
622
+ curabitur eleifend wisi iaculis ipsum.
623
+
624
+ # Allowed
625
+ Curabitur eleifend wisi iaculis ipsum.
626
+ ....
627
+
628
+ === Commit Body Phrase
629
+
630
+ [options="header"]
631
+ |===
632
+ | Enabled | Severity | Defaults
633
+ | true | error | excludes: (see configuration)
634
+ |===
635
+
636
+ Ensures non-descriptive words/phrases are avoided in order to keep commit message bodies informative
637
+ and specific. The exclude list is case insensitive. Detection of excluded words/phrases is case
638
+ insensitive as well. Example:
639
+
640
+ ....
641
+ # Disallowed
642
+
643
+ Obviously, the existing implementation was too simple for my tastes. Of course, this couldn't be
644
+ allowed. Everyone knows the correct way to implement this code is to do just what I've added in
645
+ this commit. Easy!
646
+
647
+ # Allowed
648
+
649
+ Necessary to fix due to a bug detected in production. The included implementation fixes the bug
650
+ and provides the missing spec to ensure this doesn't happen again.
651
+ ....
652
+
653
+ === Commit Body Presence
654
+
655
+ [options="header"]
656
+ |===
657
+ | Enabled | Severity | Defaults
658
+ | false | warn | minimum: 1
659
+ |===
660
+
661
+ Ensures a minimum number of lines are present within the commit body. Lines with empty characters
662
+ (i.e. whitespace, carriage returns, etc.) are considered to be empty.
663
+
664
+ Automatically ignores _fixup!_ commits as they are not meant to have bodies.
665
+
666
+ === Commit Body Single Bullet
667
+
668
+ [options="header"]
669
+ |===
670
+ | Enabled | Severity | Defaults
671
+ | true | error | includes: `"\\-"`
672
+ |===
673
+
674
+ Ensures a single bullet is never used when a paragraph could be used instead. Example:
675
+
676
+ ....
677
+ # Disallowed
678
+
679
+ - Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
680
+ quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam.
681
+
682
+ # Allowed
683
+
684
+ Pellentque morbi-trist sentus et netus et malesuada fames ac turpis egestas. Vestibulum tortor
685
+ quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu_libero sit amet quam.
686
+ ....
687
+
688
+ === Commit Subject Length
689
+
690
+ [options="header"]
691
+ |===
692
+ | Enabled | Severity | Defaults
693
+ | true | error | length: 72
694
+ |===
695
+
696
+ Ensures the commit subject length is no more than 72 characters in length. This default is more
697
+ lenient than the link:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[50/72
698
+ rule] as it gives one the ability to formulate a more descriptive subject line without being too
699
+ wordy or suffer being word wrapped.
700
+
701
+ Automatically ignores _fixup!_ or _squash!_ commit prefixes when calculating subject length.
702
+
703
+ === Commit Subject Prefix
704
+
705
+ [options="header"]
706
+ |===
707
+ | Enabled | Severity | Defaults
708
+ | true | error | includes: (see below)
709
+ |===
710
+
711
+ Ensures the commit subject uses consistent prefixes that explain _what_ is being committed. The
712
+ `includes` are _case sensitive_ and default to the following prefixes:
713
+
714
+ * *Fixed* - Identifies what was fixed. The commit should be as small as possible and consist of
715
+ changes to implementation and spec only. In some cases this might be a single line or file change.
716
+ The important point is the change is applied to existing code which corrects behavior that wasn't
717
+ properly implemented earlier.
718
+ * *Removed* - Identifies what was removed. The commit should be as small as possible and consist
719
+ only of removed lines/files from the existing implementation. This might also mean breaking
720
+ changes requiring the publishing of a _major_ version release in the future.
721
+ * *Added* - Identifies what was added. The commit should be as small as possible and consist of
722
+ implementation and spec. Otherwise, it might be a change to an existing file which adds new
723
+ behavior.
724
+ * *Updated* - Identifies what was updated. The commit should be as small as possible and _not add
725
+ or fix_ existing behavior. This can sometimes be a grey area but is typically reserved for updates
726
+ to documentation, code comments, dependencies, etc.
727
+ * *Refactored* - Identifies what was refactored. The commit should be as small as possible and only
728
+ improve existing functionality while avoiding changes in behavior (especially to public API
729
+ that might effect downstream dependencies). Refactored code should never break existing specs.
730
+
731
+ In practice, using a prefix other than what has been detailed above to explain _what_ is being
732
+ committed is never needed. These prefixes are not only short and easy to remember but also have the
733
+ added benefit of categorizing the commits for building release notes, change logs, etc. This becomes
734
+ handy when coupled with another tool, link:https://www.alchemists.io/projects/milestoner[Milestoner],
735
+ for producing consistent project milestones and Git tag histories.
736
+
737
+ Automatically ignores _fixup!_ or _squash!_ commit prefixes when used as a Git Hook in order to not
738
+ disturb interactive rebase workflows.
739
+
740
+ === Commit Subject Suffix
741
+
742
+ [options="header"]
743
+ |===
744
+ | Enabled | Severity | Defaults
745
+ | true | error | excludes: `["\\.", "\\?", "\\!"]`
746
+ |===
747
+
748
+ Ensures commit subjects are suffixed consistently. The exclude list _is_ case sensitive and prevents
749
+ the use of punctuation. This is handy when coupled with a tool, like
750
+ link:https://www.alchemists.io/projects/milestoner[Milestoner], which automates project milestone
751
+ releases.
752
+
753
+ === Commit Trailer Collaborator Capitalization
754
+
755
+ [options="header"]
756
+ |===
757
+ | Enabled | Severity | Defaults
758
+ | false | error | none
759
+ |===
760
+
761
+ Ensures collaborator name is properly capitalized. Example:
762
+
763
+ ....
764
+ # Disallowed
765
+ shepherd derrial book
766
+
767
+ # Allowed
768
+ Shepherd Derrial Book
769
+ ....
770
+
771
+ === Commit Trailer Collaborator Duplication
772
+
773
+ [options="header"]
774
+ |===
775
+ | Enabled | Severity | Defaults
776
+ | false | error | none
777
+ |===
778
+
779
+ Ensures collaborator trailers are not duplicated. Example:
780
+
781
+ ....
782
+ # Disallowed
783
+ Co-Authored-By: Shepherd Derrial Book <shepherd@firefly.com>
784
+ Co-Authored-By: Shepherd Derrial Book <shepherd@firefly.com>
785
+
786
+ # Allowed
787
+ Co-Authored-By: Malcolm Reynolds <malcolm@firefly.com>
788
+ Co-Authored-By: Shepherd Derrial Book <shepherd@firefly.com>
789
+ ....
790
+
791
+ === Commit Trailer Collaborator Email
792
+
793
+ [options="header"]
794
+ |===
795
+ | Enabled | Severity | Defaults
796
+ | false | error | none
797
+ |===
798
+
799
+ Ensures collaborator email address is valid for commit trailer.
800
+
801
+ ....
802
+ # Disallowed
803
+ Co-Authored-By: River Tam <invalid>
804
+
805
+ # Allowed
806
+ Co-Authored-By: River Tam <river@firefly.com>
807
+ ....
808
+
809
+ === Commit Trailer Collaborator Key
810
+
811
+ [options="header"]
812
+ |===
813
+ | Enabled | Severity | Defaults
814
+ | false | error | includes: `["Co-Authored-By"]`
815
+ |===
816
+
817
+ Ensures collaborator trailer key is correct format.
818
+
819
+ ....
820
+ # Disallowed
821
+ Co-authored-by: River Tam <river@firefly.com>
822
+
823
+ # Allowed
824
+ Co-Authored-By: River Tam <river@firefly.com>
825
+ ....
826
+
827
+ === Commit Trailer Collaborator Name
828
+
829
+ [options="header"]
830
+ |===
831
+ | Enabled | Severity | Defaults
832
+ | false | error | minimum: 2
833
+ |===
834
+
835
+ Ensures collaborator name consists of, at least, a first and last name. Example:
836
+
837
+ ....
838
+ # Disallowed
839
+ Co-Authored-By: River <river@firefly.com>
840
+
841
+ # Allowed
842
+ Co-Authored-By: River Tam <river@firefly.com>
843
+ ....
844
+
845
+ == Style Guide
846
+
847
+ In addition to what is described above and automated for you, the following style guide is also
848
+ worth considering:
849
+
850
+ === General
851
+
852
+ * Use a {git_rebase_workflow_link} instead of a Git merge workflow.
853
+ * Use `git commit --amend` when fixing a previous commit, addressing code review feedback, etc.
854
+ * Use `git commit --fixup` when fixing an earlier commit, addressing code review feedback, etc., and
855
+ don't need to modify the original commit message.
856
+ * Use `git commit --squash` when fixing an earlier commit, addressing code review feedback, etc.,
857
+ and want to combine multiple commit messages into a single commit message. _Avoid using squash to
858
+ blindly combine multiple commit messages without editing them into a single, coherent message._
859
+ * Use `git rebase --interactive` when cleaning up commit history, order, messages, etc. This should
860
+ be done prior to submitting a code review or when code review feedback has been addressed and
861
+ you are ready to rebase onto `master`.
862
+ * Use `git push --force-with-lease` instead of `git push --force` when pushing changes after an
863
+ interactive rebasing session.
864
+ * Avoid checking in development-specific configuration files (add to `.gitignore` instead).
865
+ * Avoid checking in sensitive information (i.e. security keys, passphrases, etc).
866
+ * Avoid "WIP" (a.k.a. "Work in Progress") commits and/or code review labels. Be confident with your
867
+ code and colleagues' time. Use branches, stashes, etc. instead -- share a link to a feature branch
868
+ diff if you have questions/concerns during development.
869
+ * Avoid using link:https://git-scm.com/book/en/v2/Git-Tools-Submodules[Git Submodules]. This
870
+ practice leads to complicated project cloning, deployments, maintenance, etc. Use separate
871
+ repositories to better organize and split out this work. Sophisticated package managers, like
872
+ link:https://bundler.io[Bundler] for example, exist to manage these dependencies better than what
873
+ multiple Git Submodules can accomplish.
874
+ * Avoid using link:https://git-lfs.github.com[Git LFS] for tracking binary artifacts/resources.
875
+ These files are not meant for version control and lead to large repositories that are time
876
+ consuming to clone/deploy. Use storage managers, like link:https://aws.amazon.com/s3[Amazon S3]
877
+ for example, that are better suited for binary assets that don't change often.
878
+
879
+ === Commits
880
+
881
+ * Use a commit subject that explains _what_ is being committed.
882
+ * Use a commit message body that explains _why_ the commit is necessary. Additional considerations:
883
+ ** If the commit has a dependency to the previous commit or is a precursor to the commit that will
884
+ follow, make sure to explain that.
885
+ ** Include links to dependent projects, stories, etc. if available.
886
+ * Use small, atomic commits:
887
+ ** Easier to review and provide feedback.
888
+ ** Easier to review implementation and corresponding tests.
889
+ ** Easier to document with detailed subject messages (especially when grouped together in a pull
890
+ request).
891
+ ** Easier to reword, edit, squash, fix, or drop when interactively rebasing.
892
+ ** Easier to combine together versus tearing apart a larger commit into smaller commits.
893
+ * Use logically ordered commits:
894
+ ** Each commit should tell a story and be a logical building block to the next commit.
895
+ ** Each commit, when reviewed in order, should be able to explain _how_ the feature or bug fix was
896
+ completed and implemented properly.
897
+
898
+ === Branches
899
+
900
+ * Use feature branches for new work.
901
+ * Maintain branches by rebasing upon `master` on a regular basis.
902
+
903
+ === Tags
904
+
905
+ * Use tags to denote milestones/releases:
906
+ ** Makes it easier to record milestones and capture associated release notes.
907
+ ** Makes it easier to compare differences between versions.
908
+ ** Provides a starting point for debugging production issues (if any).
909
+
910
+ === Rebases
911
+
912
+ * Avoid rebasing a shared branch. If you must do this, clear communication should be used to warn
913
+ those ahead of time, ensure that all of their work is checked in, and that their local branch is
914
+ deleted first.
915
+
916
+ === Hooks
917
+
918
+ * Use hooks to augment and automate your personal workflow such as checking code quality, detecting
919
+ forgotten debug statements, etc.
920
+ * Use hooks globally rather than locally per project. Doing this applies the same functionality
921
+ across all projects automatically, reduces maintenance per project, and provides consistency
922
+ across all projects. This can best be managed via your
923
+ link:https://github.com/bkuhlmann/dotfiles/tree/master/home_files/.config/git/hooks[Dotfiles].
924
+ * Avoid forcing global or local project hooks as a team-wide mandate. Hooks are a personal tool much
925
+ like editors or other tools one choose to do their work. For team consistency, use a continuous
926
+ integration build server instead.
927
+
928
+ === Code Reviews
929
+
930
+ There are two objectives each code review should achieve:
931
+
932
+ . *Quality*: Ensures changes are of highest quality that adhere to team standards while enhancing
933
+ the customer experience and not disrupting their workflow.
934
+ . *Education*: Provides a chance for everyone on the team to learn more about the architecture,
935
+ product/service, and how each member of the team implements a solution. This is your chance to
936
+ ask questions and learn how to be a better engineer so take advantage of it.
937
+
938
+ In addition to the objectives above, the following guidelines are worth following:
939
+
940
+ * Keep code reviews short and easy to review:
941
+ ** Provide a high level overview that answers _why_ the code review is necessary.
942
+ ** Provide a link to the issue/task that prompted the code review (if any).
943
+ ** Provide screenshots/screencasts if possible.
944
+ ** Ensure commits within the code review are related to the purpose of the code review.
945
+ ** Prefer code reviews at about 250 lines in order to keep the quality of the code review and defect
946
+ detection high.
947
+ ** Avoid working on a large issue without getting feedback first in order to not overwhelm/surprise
948
+ the maintainers. More discussion up front will help ensure your work has a faster chance of
949
+ acceptance.
950
+ * Review and rebase code reviews quickly:
951
+ ** Maintain a consistent but reasonable pace -- Review morning, noon, and night.
952
+ ** Avoid letting code reviews linger more than a day. Otherwise, you risk hampering moral and
953
+ diminishing the productivity of the team.
954
+ * Use emojis, with a format of `<emoji> <feedback>`, to identify the kinds of feedback used during
955
+ the review process:
956
+ ** đŸĩ (`:tea:`) - Signifies you are starting the code review. This is _non-blocking_ and
957
+ informational. Useful when reading over a code review with a large number of commits, complex
958
+ code, requires additional testing by the reviewer, etc.
959
+ ** ⭐ī¸ (`:star:`) - Signifies code that is liked, favorited, remarkable, etc. This feedback is
960
+ _non-blocking_ and is always meant to be positive/uplifting.
961
+ ** ℹī¸ (`:information_source:`) - Signifies informational feedback that is
962
+ _non-blocking_. Can also be used to let one know you are done reviewing but haven't approved yet
963
+ (due to feedback that needs addressing), rebasing a code review and then merging, waiting for a
964
+ blocking code review to be resolved, status updates to the code review, etc.
965
+ ** 💭 (`:thought_balloon:`) - Signifies inquisitive intent that is _non-blocking_.
966
+ Useful when asking questions and/or probing deeper into implementation details to learn more.
967
+ ** 🔤 (`:abc:`) - Signifies detection of a misspelling with suggested correction. This is
968
+ _blocking_ feedback that is easy to correct.
969
+ ** 🎨 (`:art:`) - Signifies an issue with code style and/or code quality. This can be _blocking_
970
+ or _non-blocking_ feedback. It is up to the discretion of the author on how to address the
971
+ feedback but encouraged that the feedback is incorporated or at least discussed. Generally,
972
+ these situations are automatically detected via code linters but there are occasions where
973
+ there is ambiguity in which linters can't catch.
974
+ ** 🏛 (`:classical_building:`) - Signifies an issue with the architecture of the
975
+ implementation. This is _blocking_ and requires immediate correction. The reviewer should
976
+ provide a suggested solution and/or links to patterns, articles, etc. that might help the author
977
+ fix the implementation. Pairing is encouraged if feedback is vast and/or complex.
978
+ ** 🔒 (`:lock:`) - Signifies a security violation that would damage us and/or our customers. This is
979
+ _blocking_ feedback and must be addressed immediately.
980
+ ** 💡 (`:bulb:`) - Indicates a helpful tip or trick for improving the code. This can be
981
+ _blocking_ or _non-blocking_ feedback and is left up to the author to decide. Generally, it is a
982
+ good idea to address and resolve the feedback.
983
+ ** 🙇 (`:bow:`) - Indicates thankfulness of the feedback received. This is _non-blocking_ and
984
+ always meant as a response to helpful feedback.
985
+ ** ✅ (`:white_check_mark:`) - Signifies code review approval. The author can
986
+ rebase onto `master` and delete the feature branch at this point.
987
+ * Use face-to-face communication if a code review's written discussion gets lengthy/noisy.
988
+ * Create new tasks/actions if additional features are discovered during a code review to avoid
989
+ delaying code review acceptance. Return to the code review once tasks have been logged.
990
+ * The author, not the reviewer, should rebase the feature branch onto `master` upon approval.
991
+ * Avoid reviewing your own code review before rebasing onto `master`. Have another pair of eyes
992
+ review your code first.
993
+ * Ensure the following criteria is met before rebasing your feature branch to `master`:
994
+ ** Ensure all `fixup!` and `squash!` commits are interactively rebased. _Avoid rebasing these onto
995
+ the `master` branch!_
996
+ ** Ensure your feature branch is rebased upon `master`.
997
+ ** Ensure all tests and code quality checks are passing.
998
+ ** Ensure the feature branch is deleted after being successfully rebased.
999
+
1000
+ === GitHub
1001
+
1002
+ When using GitHub, enforce a rebase workflow for all of your GitHub projects (_highly recommended_).
1003
+ You can do this via your project options (i.e. `https://github.com/<username/<project>/settings`)
1004
+ and editing your merge options for code reviews as follows:
1005
+
1006
+ image::https://www.alchemists.io/images/projects/git-lint/screenshots/github-settings-options.png[GitHub Merge Options]
1007
+
1008
+ In addition to the above, you'll want to add _branch_ protection rules for your `master` branch. To
1009
+ do this, follow these steps:
1010
+
1011
+ . Visit your branch settings (i.e. `https://github.com/<username>/<project>/settings/branches`).
1012
+ . Click the _Add rule_ button.
1013
+ . For _branch name pattern_, enter: `master`.
1014
+ . Check _Require pull request reviews before merging_.
1015
+ . Set _Required approving reviews_ to `2` as a minimum.
1016
+ . Check _Dismiss stale pull request approvals when new commits are pushed_.
1017
+ . Check _Require review from Code Owners_.
1018
+ . Check _Require status checks to pass before merging_.
1019
+ . Check _Require branches to be up to date before merging_.
1020
+ . Check _Require linear history_ (pairs well with the merge options mentioned above).
1021
+ . Check _Include administrators_.
1022
+ . Uncheck _Require signed commits_ (only necessary for tags).
1023
+ . Uncheck _Allow force pushes_.
1024
+ . Uncheck _Allow deletions_.
1025
+
1026
+ With the above applied, you should have the following result:
1027
+
1028
+ image::https://www.alchemists.io/images/projects/git-lint/screenshots/github-settings-branch_protections.png[GitHub Branch Protections]
1029
+
1030
+ Applying the above changes will help maintain a clean Git history.
1031
+
1032
+ == Tests
1033
+
1034
+ To test, run:
1035
+
1036
+ [source,bash]
1037
+ ----
1038
+ bundle exec rake
1039
+ ----
1040
+
1041
+ == Versioning
1042
+
1043
+ Read link:https://semver.org[Semantic Versioning] for details. Briefly, it means:
1044
+
1045
+ * Major (X.y.z) - Incremented for any backwards incompatible public API changes.
1046
+ * Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.
1047
+ * Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.
1048
+
1049
+ == Code of Conduct
1050
+
1051
+ Please note that this project is released with a link:CODE_OF_CONDUCT.adoc[CODE OF CONDUCT]. By
1052
+ participating in this project you agree to abide by its terms.
1053
+
1054
+ == Contributions
1055
+
1056
+ Read link:CONTRIBUTING.adoc[CONTRIBUTING] for details.
1057
+
1058
+ == License
1059
+
1060
+ Read link:LICENSE.adoc[LICENSE] for details.
1061
+
1062
+ == History
1063
+
1064
+ Read link:CHANGES.adoc[CHANGES] for details.
1065
+
1066
+ == Credits
1067
+
1068
+ Engineered by link:https://www.alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].