jawshooah-overcommit 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/bin/overcommit +8 -0
  3. data/config/default.yml +275 -0
  4. data/config/starter.yml +31 -0
  5. data/lib/overcommit.rb +20 -0
  6. data/lib/overcommit/cli.rb +205 -0
  7. data/lib/overcommit/configuration.rb +183 -0
  8. data/lib/overcommit/configuration_loader.rb +49 -0
  9. data/lib/overcommit/configuration_validator.rb +40 -0
  10. data/lib/overcommit/constants.rb +8 -0
  11. data/lib/overcommit/exceptions.rb +35 -0
  12. data/lib/overcommit/git_repo.rb +147 -0
  13. data/lib/overcommit/hook/base.rb +174 -0
  14. data/lib/overcommit/hook/commit_msg/base.rb +11 -0
  15. data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +18 -0
  16. data/lib/overcommit/hook/commit_msg/hard_tabs.rb +13 -0
  17. data/lib/overcommit/hook/commit_msg/russian_novel.rb +14 -0
  18. data/lib/overcommit/hook/commit_msg/single_line_subject.rb +12 -0
  19. data/lib/overcommit/hook/commit_msg/text_width.rb +38 -0
  20. data/lib/overcommit/hook/commit_msg/trailing_period.rb +12 -0
  21. data/lib/overcommit/hook/post_checkout/base.rb +11 -0
  22. data/lib/overcommit/hook/post_checkout/index_tags.rb +26 -0
  23. data/lib/overcommit/hook/post_commit/base.rb +11 -0
  24. data/lib/overcommit/hook/post_commit/git_guilt.rb +9 -0
  25. data/lib/overcommit/hook/pre_commit/author_email.rb +18 -0
  26. data/lib/overcommit/hook/pre_commit/author_name.rb +17 -0
  27. data/lib/overcommit/hook/pre_commit/base.rb +70 -0
  28. data/lib/overcommit/hook/pre_commit/berksfile_check.rb +20 -0
  29. data/lib/overcommit/hook/pre_commit/brakeman.rb +12 -0
  30. data/lib/overcommit/hook/pre_commit/broken_symlinks.rb +15 -0
  31. data/lib/overcommit/hook/pre_commit/bundle_check.rb +25 -0
  32. data/lib/overcommit/hook/pre_commit/chamber_security.rb +11 -0
  33. data/lib/overcommit/hook/pre_commit/coffee_lint.rb +11 -0
  34. data/lib/overcommit/hook/pre_commit/css_lint.rb +11 -0
  35. data/lib/overcommit/hook/pre_commit/go_lint.rb +12 -0
  36. data/lib/overcommit/hook/pre_commit/haml_lint.rb +19 -0
  37. data/lib/overcommit/hook/pre_commit/hard_tabs.rb +14 -0
  38. data/lib/overcommit/hook/pre_commit/image_optim.rb +41 -0
  39. data/lib/overcommit/hook/pre_commit/js_hint.rb +13 -0
  40. data/lib/overcommit/hook/pre_commit/jscs.rb +22 -0
  41. data/lib/overcommit/hook/pre_commit/json_syntax.rb +22 -0
  42. data/lib/overcommit/hook/pre_commit/jsx_hint.rb +13 -0
  43. data/lib/overcommit/hook/pre_commit/jsxcs.rb +20 -0
  44. data/lib/overcommit/hook/pre_commit/local_paths_in_gemfile.rb +14 -0
  45. data/lib/overcommit/hook/pre_commit/merge_conflicts.rb +14 -0
  46. data/lib/overcommit/hook/pre_commit/pry_binding.rb +14 -0
  47. data/lib/overcommit/hook/pre_commit/python_flake8.rb +11 -0
  48. data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +45 -0
  49. data/lib/overcommit/hook/pre_commit/reek.rb +22 -0
  50. data/lib/overcommit/hook/pre_commit/rubocop.rb +19 -0
  51. data/lib/overcommit/hook/pre_commit/scss_lint.rb +19 -0
  52. data/lib/overcommit/hook/pre_commit/shell_check.rb +19 -0
  53. data/lib/overcommit/hook/pre_commit/trailing_whitespace.rb +13 -0
  54. data/lib/overcommit/hook/pre_commit/travis_lint.rb +11 -0
  55. data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +22 -0
  56. data/lib/overcommit/hook_context.rb +17 -0
  57. data/lib/overcommit/hook_context/base.rb +69 -0
  58. data/lib/overcommit/hook_context/commit_msg.rb +32 -0
  59. data/lib/overcommit/hook_context/post_checkout.rb +26 -0
  60. data/lib/overcommit/hook_context/post_commit.rb +19 -0
  61. data/lib/overcommit/hook_context/pre_commit.rb +148 -0
  62. data/lib/overcommit/hook_context/run_all.rb +39 -0
  63. data/lib/overcommit/hook_loader/base.rb +36 -0
  64. data/lib/overcommit/hook_loader/built_in_hook_loader.rb +12 -0
  65. data/lib/overcommit/hook_loader/plugin_hook_loader.rb +61 -0
  66. data/lib/overcommit/hook_runner.rb +129 -0
  67. data/lib/overcommit/hook_signer.rb +79 -0
  68. data/lib/overcommit/installer.rb +148 -0
  69. data/lib/overcommit/interrupt_handler.rb +87 -0
  70. data/lib/overcommit/logger.rb +79 -0
  71. data/lib/overcommit/message_processor.rb +132 -0
  72. data/lib/overcommit/printer.rb +116 -0
  73. data/lib/overcommit/subprocess.rb +46 -0
  74. data/lib/overcommit/utils.rb +163 -0
  75. data/lib/overcommit/version.rb +4 -0
  76. data/libexec/gerrit-change-id +174 -0
  77. data/libexec/index-tags +17 -0
  78. data/template-dir/hooks/commit-msg +81 -0
  79. data/template-dir/hooks/overcommit-hook +81 -0
  80. data/template-dir/hooks/post-checkout +81 -0
  81. data/template-dir/hooks/pre-commit +81 -0
  82. metadata +184 -0
@@ -0,0 +1,19 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `rubocop` against any modified Ruby files.
3
+ class Rubocop < Base
4
+ MESSAGE_TYPE_CATEGORIZER = lambda do |type|
5
+ type.include?('W') ? :warning : :error
6
+ end
7
+
8
+ def run
9
+ result = execute(%W[#{executable} --format=emacs --force-exclusion] + applicable_files)
10
+ return :pass if result.success?
11
+
12
+ extract_messages(
13
+ result.stdout.split("\n"),
14
+ /^(?<file>[^:]+):(?<line>\d+):[^ ]+ (?<type>[^ ]+)/,
15
+ MESSAGE_TYPE_CATEGORIZER,
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `scss-lint` against any modified SCSS files.
3
+ class ScssLint < Base
4
+ MESSAGE_TYPE_CATEGORIZER = lambda do |type|
5
+ type.include?('W') ? :warning : :error
6
+ end
7
+
8
+ def run
9
+ result = execute([executable] + applicable_files)
10
+ return :pass if result.success?
11
+
12
+ extract_messages(
13
+ result.stdout.split("\n"),
14
+ /^(?<file>[^:]+):(?<line>\d+)[^ ]* (?<type>[^ ]+)/,
15
+ MESSAGE_TYPE_CATEGORIZER,
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `shellcheck` against any modified shell script files.
3
+ class ShellCheck < Base
4
+ MESSAGE_TYPE_CATEGORIZER = lambda do |type|
5
+ type.include?('note') ? :warning : :error
6
+ end
7
+
8
+ def run
9
+ result = execute(%W[#{executable} --format=gcc] + applicable_files)
10
+ return :pass if result.success?
11
+
12
+ extract_messages(
13
+ result.stdout.split("\n"),
14
+ /^(?<file>[^:]+):(?<line>\d+):[^ ]+ (?<type>[^ ]+)/,
15
+ MESSAGE_TYPE_CATEGORIZER,
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Checks for trailing whitespace in files.
3
+ class TrailingWhitespace < Base
4
+ def run
5
+ result = execute(%w[grep -IHn \s$] + applicable_files)
6
+ unless result.stdout.empty?
7
+ return :fail, "Trailing whitespace detected:\n#{result.stdout}"
8
+ end
9
+
10
+ :pass
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `travis-lint` against any modified Travis CI files.
3
+ class TravisLint < Base
4
+ def run
5
+ result = execute([executable, 'lint'] + applicable_files)
6
+ return :pass if result.success?
7
+
8
+ [:fail, (result.stdout + result.stderr).strip]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ require 'yaml'
2
+
3
+ module Overcommit::Hook::PreCommit
4
+ # Checks the syntax of any modified YAML files.
5
+ class YamlSyntax < Base
6
+ def run
7
+ output = []
8
+
9
+ applicable_files.each do |file|
10
+ begin
11
+ YAML.load_file(file)
12
+ rescue ArgumentError => e
13
+ output << "#{e.message} parsing #{file}"
14
+ end
15
+ end
16
+
17
+ return :pass if output.empty?
18
+
19
+ [:fail, output]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ # Utility module which manages the creation of {HookContext}s.
2
+ module Overcommit::HookContext
3
+ def self.create(hook_type, config, args)
4
+ hook_type_class = Overcommit::Utils.camel_case(hook_type)
5
+ underscored_hook_type = Overcommit::Utils.snake_case(hook_type)
6
+
7
+ require "overcommit/hook_context/#{underscored_hook_type}"
8
+
9
+ Overcommit::HookContext.const_get(hook_type_class).new(config, args)
10
+ rescue LoadError, NameError => error
11
+ # Could happen when a symlink was created for a hook type Overcommit does
12
+ # not yet support.
13
+ raise Overcommit::Exceptions::HookContextLoadError,
14
+ "Unable to load '#{hook_type}' hook context: '#{error}'",
15
+ error.backtrace
16
+ end
17
+ end
@@ -0,0 +1,69 @@
1
+ require 'set'
2
+
3
+ module Overcommit::HookContext
4
+ # Contains helpers related to the context with which a hook is being run.
5
+ #
6
+ # It acts as an adapter to the arguments passed to the hook, as well as
7
+ # context-specific information such as staged files, providing a single source
8
+ # of truth for this context.
9
+ #
10
+ # This is also important to house in a separate object so that any
11
+ # calculations can be memoized across all hooks in a single object, which
12
+ # helps with performance.
13
+ class Base
14
+ # @param config [Overcommit::Configuration]
15
+ # @param args [Array<String>]
16
+ def initialize(config, args)
17
+ @config = config
18
+ @args = args
19
+ end
20
+
21
+ # Returns the camel-cased type of this hook (e.g. PreCommit)
22
+ def hook_class_name
23
+ self.class.name.split('::').last
24
+ end
25
+
26
+ # Returns the snake-cased type of this hook (e.g. pre_commit)
27
+ def hook_type_name
28
+ Overcommit::Utils.snake_case(hook_class_name)
29
+ end
30
+
31
+ # Returns the actual name of the hook script being run (e.g. pre-commit).
32
+ def hook_script_name
33
+ hook_type_name.gsub('_', '-')
34
+ end
35
+
36
+ # Initializes anything related to the environment.
37
+ #
38
+ # This is called before the hooks are run by the [HookRunner]. Different
39
+ # hook types can perform different setup.
40
+ def setup_environment
41
+ # Implemented by subclass
42
+ end
43
+
44
+ # Resets the environment to an appropriate state.
45
+ #
46
+ # This is called after the hooks have been run by the [HookRunner].
47
+ # Different hook types can perform different cleanup operations, which are
48
+ # intended to "undo" the results of the call to {#setup_environment}.
49
+ def cleanup_environment
50
+ # Implemented by subclass
51
+ end
52
+
53
+ # Returns a list of files that have been modified.
54
+ #
55
+ # By default, this returns an empty list. Subclasses should implement if
56
+ # there is a concept of files changing for the type of hook being run.
57
+ def modified_files
58
+ []
59
+ end
60
+
61
+ # Returns a set of lines that have been modified for a file.
62
+ #
63
+ # By default, this returns an empty set. Subclasses should implement if
64
+ # there is a concept of files changing for the type of hook being run.
65
+ def modified_lines(_file)
66
+ Set.new
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,32 @@
1
+ module Overcommit::HookContext
2
+ # Contains helpers related to contextual information used by commit-msg hooks.
3
+ class CommitMsg < Base
4
+ # User commit message stripped of comments and diff (from verbose output).
5
+ def commit_message
6
+ commit_message_lines.join
7
+ end
8
+
9
+ # Updates the commit message to the specified text.
10
+ def update_commit_message(message)
11
+ ::File.open(commit_message_file, 'w') do |file|
12
+ file.write(message)
13
+ end
14
+ end
15
+
16
+ def commit_message_lines
17
+ raw_commit_message_lines.
18
+ reject { |line| line =~ /^#/ }.
19
+ take_while { |line| !line.start_with?('diff --git') }
20
+ end
21
+
22
+ def commit_message_file
23
+ @args[0]
24
+ end
25
+
26
+ private
27
+
28
+ def raw_commit_message_lines
29
+ ::IO.readlines(commit_message_file)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ module Overcommit::HookContext
2
+ # Contains helpers related to contextual information used by post-checkout
3
+ # hooks.
4
+ class PostCheckout < Base
5
+ # Returns the ref of the HEAD that we transitioned from.
6
+ def previous_head
7
+ @args[0]
8
+ end
9
+
10
+ # Returns the ref of the new current HEAD.
11
+ def new_head
12
+ @args[1]
13
+ end
14
+
15
+ # Returns whether this checkout was the result of changing/updating a
16
+ # branch.
17
+ def branch_checkout?
18
+ @args[2].to_i == 1
19
+ end
20
+
21
+ # Returns whether this checkout was for a single file.
22
+ def file_checkout?
23
+ !branch_checkout?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ module Overcommit::HookContext
2
+ # Contains helpers related to contextual information used by post-commit
3
+ # hooks.
4
+ class PostCommit < Base
5
+ # Get a list of added, copied, or modified files that have been staged.
6
+ # Renames and deletions are ignored, since there should be nothing to check.
7
+ def modified_files_last_commit
8
+ @modified_files_last_commit ||= Overcommit::GitRepo.modified_files_last_commit
9
+ end
10
+
11
+ # Returns the set of line numbers corresponding to the lines that were
12
+ # changed in a specified file.
13
+ def modified_lines_in_file_last_commit(file)
14
+ @modified_lines_last_commit ||= {}
15
+ @modified_lines_last_commit[file] ||=
16
+ Overcommit::GitRepo.extract_modified_lines_last_commit(file)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,148 @@
1
+ require 'fileutils'
2
+ require 'set'
3
+
4
+ module Overcommit::HookContext
5
+ # Contains helpers related to contextual information used by pre-commit hooks.
6
+ #
7
+ # This includes staged files, which lines of those files have been modified,
8
+ # etc. It is also responsible for saving/restoring the state of the repo so
9
+ # hooks only inspect staged changes.
10
+ class PreCommit < Base
11
+ # Stash unstaged contents of files so hooks don't see changes that aren't
12
+ # about to be committed.
13
+ def setup_environment
14
+ store_modified_times
15
+ Overcommit::GitRepo.store_merge_state
16
+ Overcommit::GitRepo.store_cherry_pick_state
17
+
18
+ if !initial_commit? && any_changes?
19
+ @stash_attempted = true
20
+
21
+ result = Overcommit::Utils.execute(
22
+ %w[git stash save --keep-index --quiet] +
23
+ ["Overcommit: Stash of repo state before hook run at #{Time.now}"]
24
+ )
25
+
26
+ unless result.success?
27
+ # Failure to stash in this case is likely due to a configuration
28
+ # issue (e.g. author/email not set or GPG signing key incorrect)
29
+ raise Overcommit::Exceptions::HookSetupFailed,
30
+ "Unable to setup environment for #{hook_script_name} hook run:" \
31
+ "\nSTDOUT:#{result.stdout}\nSTDERR:#{result.stderr}"
32
+ end
33
+
34
+ @changes_stashed = true
35
+ end
36
+
37
+ # While running the hooks make it appear as if nothing changed
38
+ restore_modified_times
39
+ end
40
+
41
+ # Restore unstaged changes and reset file modification times so it appears
42
+ # as if nothing ever changed.
43
+ #
44
+ # We want to restore the modification times for each of the files after
45
+ # every step to ensure as little time as possible has passed while the
46
+ # modification time on the file was newer. This helps us play more nicely
47
+ # with file watchers.
48
+ def cleanup_environment
49
+ unless initial_commit? || (@stash_attempted && !@changes_stashed)
50
+ clear_working_tree # Ensure working tree is clean before restoring it
51
+ restore_modified_times
52
+ end
53
+
54
+ if @changes_stashed
55
+ restore_working_tree
56
+ restore_modified_times
57
+ end
58
+
59
+ Overcommit::GitRepo.restore_merge_state
60
+ Overcommit::GitRepo.restore_cherry_pick_state
61
+ restore_modified_times
62
+ end
63
+
64
+ # Get a list of added, copied, or modified files that have been staged.
65
+ # Renames and deletions are ignored, since there should be nothing to check.
66
+ def modified_files
67
+ @modified_files ||= Overcommit::GitRepo.modified_files(staged: true)
68
+ end
69
+
70
+ # @deprecated
71
+ # TODO: Remove this once we've moved all existing hooks to stop using this
72
+ # endpoint
73
+ def modified_lines(file)
74
+ modified_lines_in_file(file)
75
+ end
76
+
77
+ # Returns the set of line numbers corresponding to the lines that were
78
+ # changed in a specified file.
79
+ def modified_lines_in_file(file)
80
+ @modified_lines ||= {}
81
+ @modified_lines[file] ||=
82
+ Overcommit::GitRepo.extract_modified_lines(file, staged: true)
83
+ end
84
+
85
+ private
86
+
87
+ # Clears the working tree so that the stash can be applied.
88
+ def clear_working_tree
89
+ result = Overcommit::Utils.execute(%w[git reset --hard])
90
+ unless result.success?
91
+ raise Overcommit::Exceptions::HookCleanupFailed,
92
+ "Unable to cleanup working tree after #{hook_script_name} hooks run:" \
93
+ "\nSTDOUT:#{result.stdout}\nSTDERR:#{result.stderr}"
94
+ end
95
+ end
96
+
97
+ # Applies the stash to the working tree to restore the user's state.
98
+ def restore_working_tree
99
+ result = Overcommit::Utils.execute(%w[git stash pop --index --quiet])
100
+ unless result.success?
101
+ raise Overcommit::Exceptions::HookCleanupFailed,
102
+ "Unable to restore working tree after #{hook_script_name} hooks run:" \
103
+ "\nSTDOUT:#{result.stdout}\nSTDERR:#{result.stderr}"
104
+ end
105
+ end
106
+
107
+ # Returns whether there are any changes to the working tree, staged or
108
+ # otherwise.
109
+ def any_changes?
110
+ modified_files = `git status -z --untracked-files=no`.
111
+ split("\0").
112
+ map { |line| line.gsub(/[^\s]+\s+(.+)/, '\\1') }
113
+
114
+ modified_files.any?
115
+ end
116
+
117
+ # Returns whether the current git branch is empty (has no commits).
118
+ def initial_commit?
119
+ return @initial_commit unless @initial_commit.nil?
120
+ @initial_commit = Overcommit::GitRepo.initial_commit?
121
+ end
122
+
123
+ # Stores the modification times for all modified files to make it appear like
124
+ # they never changed.
125
+ #
126
+ # This prevents (some) editors from complaining about files changing when we
127
+ # stash changes before running the hooks.
128
+ def store_modified_times
129
+ @modified_times = {}
130
+
131
+ modified_files.each do |file|
132
+ next if Overcommit::Utils.broken_symlink?(file)
133
+ @modified_times[file] = File.mtime(file)
134
+ end
135
+ end
136
+
137
+ # Restores the file modification times for all modified files to make it
138
+ # appear like they never changed.
139
+ def restore_modified_times
140
+ modified_files.each do |file|
141
+ next if Overcommit::Utils.broken_symlink?(file)
142
+ next unless File.exist?(file)
143
+ time = @modified_times[file]
144
+ File.utime(time, time, file)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,39 @@
1
+ require 'set'
2
+
3
+ module Overcommit::HookContext
4
+ # Simulates a pre-commit context pretending that all files have been changed.
5
+ #
6
+ # This results in pre-commit hooks running against the entire repository,
7
+ # which is useful for automated CI scripts.
8
+ class RunAll < Base
9
+ EMPTY_SET = Set.new
10
+
11
+ def modified_files
12
+ all_files
13
+ end
14
+
15
+ # Return an empty set since in this context the user didn't actually touch
16
+ # any lines.
17
+ def modified_lines_in_file(_file)
18
+ EMPTY_SET
19
+ end
20
+
21
+ def hook_class_name
22
+ 'PreCommit'
23
+ end
24
+
25
+ def hook_type_name
26
+ 'pre_commit'
27
+ end
28
+
29
+ def hook_script_name
30
+ 'pre-commit'
31
+ end
32
+
33
+ private
34
+
35
+ def all_files
36
+ @all_files ||= Overcommit::GitRepo.all_files
37
+ end
38
+ end
39
+ end