Skip to content

Instantly share code, notes, and snippets.

@davidstosik
Last active April 11, 2019 10:46
Show Gist options
  • Save davidstosik/bf696ea7356884dead30d2ab2a1c62bf to your computer and use it in GitHub Desktop.
Save davidstosik/bf696ea7356884dead30d2ab2a1c62bf to your computer and use it in GitHub Desktop.
Bundler and Yarn update git hooks

Git hooks for Ruby on Rails

Tired of forgetting to run bundle after you pulled a branch?

Tired of getting Yarn's integrity error message because you forgot bin/yarn?

Just have Git run those for you after most Git operations that would change Gemfile.lock or package.json!

Install

  • Put post-checkout, post-merge (no .rb extension) and utils/ inside .git/hooks
  • chmod u+x .git/hooks/post-checkout .git/hooks/post-merge

Caveats

  • You'll need a bit more time to get your prompt back, but chances are, you would run those commands anyway, right?
  • There is no git hook that can run after a git reset operation.
# .git/hooks/post-checkout
#!/usr/bin/env ruby
require_relative "utils/changed_files"
require_relative "utils/file_change_handler"
class PostCheckout
def initialize(old_head, new_head, changing_branches)
@old_head = old_head
@new_head = new_head
@changing_branches = changing_branches
end
def run
FileChangeHandler.new(changed_files).run
end
private
attr_reader :old_head, :new_head
def changing_branches?
@changing_branches == "1"
end
def changed_files
@_changed_files ||= ChangedFiles.new(old_head, new_head)
end
end
PostCheckout.new(*ARGV).run
# .git/hooks/post-merge
#!/usr/bin/env ruby
# Remove .rb extension (used for Git syntax highlighting) and chmod u+x
require_relative "utils/changed_files"
require_relative "utils/file_change_handler"
class PostMerge
def initialize(squash_merge)
@squash_merge = squash_merge
end
def run
FileChangeHandler.new(changed_files).run
end
private
def squash_merge?
@squash_merge == "1"
end
def changed_files
@_changed_files ||= ChangedFiles.new("ORIG_HEAD", "HEAD")
end
end
PostMerge.new(*ARGV).run
#.git/hooks/utils/changed_files.rb
require "open3"
class ChangedFiles < Array
def initialize(old_head, new_head)
@old_head = old_head
@new_head = new_head
super(changed_files)
end
private
attr_reader :old_head, :new_head
def changed_files
command_output.lines.map(&:chomp)
end
def command_output
Open3.capture2(*command).tap do |output, status|
raise "There was an error" if status.exitstatus != 0
return output
end
end
def command
%w(git diff-tree -r --name-only --no-commit-id) + [old_head, new_head]
end
end
# .git/hooks/utils/file_change_handler.rb
class FileChangeHandler
def initialize(changed_files)
@changed_files = changed_files
end
def run
run_bundle
run_yarn
end
private
attr_reader :changed_files
def run_bundle
return unless changed_files.include?("Gemfile.lock")
puts "Running Bundler after git changed Gemfile.lock..."
system("bundle")
end
def run_yarn
return unless changed_files.include?("package.json")
puts "Running Yarn after git changed packages.json..."
system("bin/yarn")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment