From 34a794c4738e07558376314edd156d386d0be4b4 Mon Sep 17 00:00:00 2001 From: Daniel Luna Date: Sun, 17 Sep 2017 13:50:59 -0300 Subject: [PATCH] MessageTemplate post-checkout hook This commit adds the MessageTemplate post-checkout hook, which, when correctly configured, automatically generates a [commit message template](https://robots.thoughtbot.com/better-commit-messages-with-a-gitmessage-template) based on the branch name. Groups captured in the `branch_pattern` regex can be used in `replacement_text`; see the accompanying spec for details. Also, `replacement_text` can be a path to a file, whose text will be processed following the same rules. --- config/default.yml | 8 +++ .../hook/post_checkout/message_template.rb | 50 ++++++++++++++++ .../post_checkout/message_template_spec.rb | 58 +++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 lib/overcommit/hook/post_checkout/message_template.rb create mode 100644 spec/overcommit/hook/post_checkout/message_template_spec.rb diff --git a/config/default.yml b/config/default.yml index 2f73647d..949da070 100644 --- a/config/default.yml +++ b/config/default.yml @@ -785,6 +785,14 @@ PostCheckout: quiet: true recursive: false + MessageTemplate: + enabled: false + description: 'Write commit template message based on the new branch name' + quiet: true + recursive: false + branch_pattern: '\A.*\w+[-_](\d+).*\z' + replacement_text: '[#\1] [ci skip]' + # Hooks that run after a commit is created. PostCommit: ALL: diff --git a/lib/overcommit/hook/post_checkout/message_template.rb b/lib/overcommit/hook/post_checkout/message_template.rb new file mode 100644 index 00000000..b7a1b7f4 --- /dev/null +++ b/lib/overcommit/hook/post_checkout/message_template.rb @@ -0,0 +1,50 @@ +module Overcommit::Hook::PostCheckout + class MessageTemplate < Base + def run + Overcommit::Utils.log.debug("Checking if '#{Overcommit::GitRepo.current_branch}' matches #{branch_pattern}") + if branch_pattern.match?(Overcommit::GitRepo.current_branch) + set_commit_template + :pass + else + :warn + end + end + + def set_commit_template + Overcommit::Utils.log.debug("Writing #{git_template_filename} with #{new_template}") + File.write(git_template_filename, new_template) + `git config commit.template #{git_template_filename}` + end + + def new_template + new_template ||= Overcommit::GitRepo.current_branch.gsub(branch_pattern, replacement_text) + end + + def branch_pattern + @branch_pattern ||= + begin + pattern = config['branch_pattern'] + Regexp.new(pattern.empty? ? '\A.*\w+[-_](\d+).*\z' : pattern) + end + end + + def replacement_text + @replacement_text ||= + begin + if File.exists?(replacement_text_config) + File.read(replacement_text_config) + else + replacement_text_config + end + end + end + + def replacement_text_config + @replacement_text_config ||= config['replacement_text'] + end + + def git_template_filename + config['git_template_filename'] || 'overcommit_message_template.txt' + end + end +end diff --git a/spec/overcommit/hook/post_checkout/message_template_spec.rb b/spec/overcommit/hook/post_checkout/message_template_spec.rb new file mode 100644 index 00000000..f2b48035 --- /dev/null +++ b/spec/overcommit/hook/post_checkout/message_template_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe Overcommit::Hook::PostCheckout::MessageTemplate do + let(:config) { Overcommit::ConfigurationLoader.default_configuration } + let(:context) { double('context') } + + subject(:hook) { described_class.new(config, context) } + + before do + # stubbing this so we don't litter this repo with useless template files / + # configurations + hook.stub(:set_commit_template) + allow(Overcommit::Utils).to receive_message_chain(:log, :debug) + allow(Overcommit::GitRepo).to receive(:current_branch).and_return(new_head) + end + + let(:new_head) { 'userbeforeid-12345-branch-description' } + + describe '#run' do + context 'when the checked out branch matches the pattern' do + it { is_expected.to pass } + + context 'template contents' do + subject(:template) { hook.new_template } + + before do + hook.stub(:replacement_text).and_return('Id is: \1') + end + + it { is_expected.to eq('Id is: 12345') } + end + end + + context 'when the checked out branch does not match the pattern' do + let(:new_head) { "this shouldn't match the default pattern" } + + it { is_expected.to warn } + end + end + + describe '#replacement_text' do + subject(:replacement_text) { hook.replacement_text } + let(:replacement_template_file) { 'valid_filename.txt' } + let(:replacement) { 'Id is: \1' } + + context 'when the replacement text points to a valid filename' do + before do + hook.stub(:replacement_text_config).and_return(replacement_template_file) + File.stub(:exists?).and_return(true) + File.stub(:read).with(replacement_template_file).and_return(replacement) + end + + describe 'it reads it as the replacement template' do + it { is_expected.to eq(replacement) } + end + end + end +end