summaryrefslogtreecommitdiffstats
path: root/t/t1416-ref-transaction-hooks.sh
blob: dd003a196f718b7c5ee5f85be41f74ef7d538c32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/bin/sh

test_description='reference transaction hooks'

GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME

. ./test-lib.sh

test_expect_success setup '
	test_commit PRE &&
	PRE_OID=$(git rev-parse PRE) &&
	test_commit POST &&
	POST_OID=$(git rev-parse POST)
'

test_expect_success 'hook allows updating ref if successful' '
	git reset --hard PRE &&
	test_hook reference-transaction <<-\EOF &&
		echo "$*" >>actual
	EOF
	cat >expect <<-EOF &&
		prepared
		committed
	EOF
	git update-ref HEAD POST &&
	test_cmp expect actual
'

test_expect_success 'hook aborts updating ref in prepared state' '
	git reset --hard PRE &&
	test_hook reference-transaction <<-\EOF &&
		if test "$1" = prepared
		then
			exit 1
		fi
	EOF
	test_must_fail git update-ref HEAD POST 2>err &&
	test_grep "ref updates aborted by hook" err
'

test_expect_success 'hook gets all queued updates in prepared state' '
	test_when_finished "rm actual" &&
	git reset --hard PRE &&
	test_hook reference-transaction <<-\EOF &&
		if test "$1" = prepared
		then
			while read -r line
			do
				printf "%s\n" "$line"
			done >actual
		fi
	EOF
	cat >expect <<-EOF &&
		$ZERO_OID $POST_OID HEAD
		$ZERO_OID $POST_OID refs/heads/main
	EOF
	git update-ref HEAD POST <<-EOF &&
		update HEAD $ZERO_OID $POST_OID
		update refs/heads/main $ZERO_OID $POST_OID
	EOF
	test_cmp expect actual
'

test_expect_success 'hook gets all queued updates in committed state' '
	test_when_finished "rm actual" &&
	git reset --hard PRE &&
	test_hook reference-transaction <<-\EOF &&
		if test "$1" = committed
		then
			while read -r line
			do
				printf "%s\n" "$line"
			done >actual
		fi
	EOF
	cat >expect <<-EOF &&
		$ZERO_OID $POST_OID HEAD
		$ZERO_OID $POST_OID refs/heads/main
	EOF
	git update-ref HEAD POST &&
	test_cmp expect actual
'

test_expect_success 'hook gets all queued updates in aborted state' '
	test_when_finished "rm actual" &&
	git reset --hard PRE &&
	test_hook reference-transaction <<-\EOF &&
		if test "$1" = aborted
		then
			while read -r line
			do
				printf "%s\n" "$line"
			done >actual
		fi
	EOF
	cat >expect <<-EOF &&
		$ZERO_OID $POST_OID HEAD
		$ZERO_OID $POST_OID refs/heads/main
	EOF
	git update-ref --stdin <<-EOF &&
		start
		update HEAD POST $ZERO_OID
		update refs/heads/main POST $ZERO_OID
		abort
	EOF
	test_cmp expect actual
'

test_expect_success 'interleaving hook calls succeed' '
	test_when_finished "rm -r target-repo.git" &&

	git init --bare target-repo.git &&

	test_hook -C target-repo.git reference-transaction <<-\EOF &&
		echo $0 "$@" >>actual
	EOF

	test_hook -C target-repo.git update <<-\EOF &&
		echo $0 "$@" >>actual
	EOF

	cat >expect <<-EOF &&
		hooks/update refs/tags/PRE $ZERO_OID $PRE_OID
		hooks/reference-transaction prepared
		hooks/reference-transaction committed
		hooks/update refs/tags/POST $ZERO_OID $POST_OID
		hooks/reference-transaction prepared
		hooks/reference-transaction committed
	EOF

	git push ./target-repo.git PRE POST &&
	test_cmp expect target-repo.git/actual
'

test_expect_success 'hook captures git-symbolic-ref updates' '
	test_when_finished "rm actual" &&

	test_hook reference-transaction <<-\EOF &&
		echo "$*" >>actual
		while read -r line
		do
			printf "%s\n" "$line"
		done >>actual
	EOF

	git symbolic-ref refs/heads/symref refs/heads/main &&

	cat >expect <<-EOF &&
	prepared
	$ZERO_OID ref:refs/heads/main refs/heads/symref
	committed
	$ZERO_OID ref:refs/heads/main refs/heads/symref
	EOF

	test_cmp expect actual
'

test_expect_success 'hook gets all queued symref updates' '
	test_when_finished "rm actual" &&

	git update-ref refs/heads/branch $POST_OID &&
	git symbolic-ref refs/heads/symref refs/heads/main &&
	git symbolic-ref refs/heads/symrefd refs/heads/main &&
	git symbolic-ref refs/heads/symrefu refs/heads/main &&

	test_hook reference-transaction <<-\EOF &&
	echo "$*" >>actual
	while read -r line
	do
		printf "%s\n" "$line"
	done >>actual
	EOF

	# In the files backend, "delete" also triggers an additional transaction
	# update on the packed-refs backend, which constitutes additional reflog
	# entries.
	if test_have_prereq REFFILES
	then
		cat >expect <<-EOF
		aborted
		$ZERO_OID $ZERO_OID refs/heads/symrefd
		EOF
	else
		>expect
	fi &&

	cat >>expect <<-EOF &&
	prepared
	ref:refs/heads/main $ZERO_OID refs/heads/symref
	ref:refs/heads/main $ZERO_OID refs/heads/symrefd
	$ZERO_OID ref:refs/heads/main refs/heads/symrefc
	ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu
	committed
	ref:refs/heads/main $ZERO_OID refs/heads/symref
	ref:refs/heads/main $ZERO_OID refs/heads/symrefd
	$ZERO_OID ref:refs/heads/main refs/heads/symrefc
	ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu
	EOF

	git update-ref --no-deref --stdin <<-EOF &&
	start
	symref-verify refs/heads/symref refs/heads/main
	symref-delete refs/heads/symrefd refs/heads/main
	symref-create refs/heads/symrefc refs/heads/main
	symref-update refs/heads/symrefu refs/heads/branch ref refs/heads/main
	prepare
	commit
	EOF
	test_cmp expect actual
'

test_done