Skip to content

Commit 0ee7aef

Browse files
ChrisBrsds
authored andcommitted
[PrePush::ProtectedBranches] Implement setting destructive_only setting per branch
1 parent dbab5f2 commit 0ee7aef

File tree

3 files changed

+56
-17
lines changed

3 files changed

+56
-17
lines changed

lib/overcommit/hook/pre_push/protected_branches.rb

+40-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# frozen_string_literal: true
22

33
module Overcommit::Hook::PrePush
4-
# Prevents destructive updates to specified branches.
4+
# Prevents updates to specified branches.
5+
# Accepts a 'destructive_only' option globally or per branch
6+
# to only prevent destructive updates.
57
class ProtectedBranches < Base
68
def run
79
return :pass unless illegal_pushes.any?
@@ -17,32 +19,55 @@ def run
1719

1820
def illegal_pushes
1921
@illegal_pushes ||= pushed_refs.select do |pushed_ref|
20-
protected?(pushed_ref.remote_ref) && allow_non_destructive?(pushed_ref)
22+
protected?(pushed_ref)
2123
end
2224
end
2325

24-
def protected?(remote_ref)
26+
def protected?(ref)
27+
find_pattern(ref.remote_ref)&.destructive?(ref)
28+
end
29+
30+
def find_pattern(remote_ref)
2531
ref_name = remote_ref[%r{refs/heads/(.*)}, 1]
26-
return false if ref_name.nil?
27-
protected_branch_patterns.any? do |pattern|
28-
File.fnmatch(pattern, ref_name)
32+
return if ref_name.nil?
33+
34+
patterns.find do |pattern|
35+
File.fnmatch(pattern.to_s, ref_name)
2936
end
3037
end
3138

32-
def protected_branch_patterns
33-
@protected_branch_patterns ||= Array(config['branches']).
34-
concat(Array(config['branch_patterns']))
39+
def patterns
40+
@patterns ||= fetch_patterns
3541
end
3642

37-
def destructive_only?
43+
def fetch_patterns
44+
branch_configurations.map do |pattern|
45+
if pattern.is_a?(Hash)
46+
Pattern.new(pattern.keys.first, pattern['destructive_only'])
47+
else
48+
Pattern.new(pattern, global_destructive_only?)
49+
end
50+
end
51+
end
52+
53+
def branch_configurations
54+
config['branches'].to_a + config['branch_patterns'].to_a
55+
end
56+
57+
def global_destructive_only?
3858
config['destructive_only'].nil? || config['destructive_only']
3959
end
4060

41-
def allow_non_destructive?(ref)
42-
if destructive_only?
43-
ref.destructive?
44-
else
45-
true
61+
Pattern = Struct.new('Pattern', :name, :destructive_only) do
62+
alias_method :to_s, :name
63+
alias_method :destructive_only?, :destructive_only
64+
65+
def destructive?(ref)
66+
if destructive_only?
67+
ref.destructive?
68+
else
69+
true
70+
end
4671
end
4772
end
4873
end

spec/integration/protected_branches_spec.rb

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
enabled: true
2525
branches:
2626
- protected
27+
- protected_for_destructive_only:
28+
destructive_only: true
2729
YML
2830

2931
around do |example|

spec/overcommit/hook/pre_push/protected_branches_spec.rb

+14-2
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
let(:context) { double('context') }
1616
subject { described_class.new(config, context) }
1717

18-
let(:protected_branch_patterns) { ['master', 'release/*'] }
18+
let(:branch_configurations) do
19+
['master', 'release/*', { 'destructive_only_branch' => nil, 'destructive_only' => true }]
20+
end
1921
let(:pushed_ref) do
2022
instance_double(Overcommit::HookContext::PrePush::PushedRef)
2123
end
2224

2325
before do
24-
subject.stub(protected_branch_patterns: protected_branch_patterns)
26+
subject.stub(branch_configurations: branch_configurations)
2527
pushed_ref.stub(:remote_ref).and_return("refs/heads/#{pushed_ref_name}")
2628
context.stub(:pushed_refs).and_return([pushed_ref])
2729
end
@@ -94,6 +96,16 @@
9496
let(:pushed_ref_name) { 'release/0.1.0' }
9597
include_examples 'protected branch'
9698
end
99+
100+
context 'when branch overwrites global destructive_only' do
101+
before do
102+
pushed_ref.stub(:destructive?).and_return(true)
103+
end
104+
let(:pushed_ref_name) { 'destructive_only_branch' }
105+
let(:hook_config) { { 'destructive_only' => false } }
106+
107+
it { should fail_hook }
108+
end
97109
end
98110

99111
context 'when pushing tags' do

0 commit comments

Comments
 (0)