git-lint 1.0.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.
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].