3 # Copyright (c) 2020 Jiang Xin
5 test_description
='Test git push porcelain output'
9 # Create commits in <repo> and assign each commit's oid to shell variables
10 # given in the arguments (A, B, and C). E.g.:
12 # create_commits_in <repo> A B C
14 # NOTE: Never calling this function from a subshell since variable
15 # assignments will disappear when subshell exits.
16 create_commits_in
() {
18 if ! parent
=$
(git
-C "$repo" rev-parse HEAD^
{} --)
22 T
=$
(git
-C "$repo" write-tree
) &&
30 oid
=$
(echo $name | git
-C "$repo" commit-tree
$T)
32 oid
=$
(echo $name | git
-C "$repo" commit-tree
-p $parent $T)
39 git
-C "$repo" update-ref refs
/heads
/master
$oid
42 # Format the output of git-push, git-show-ref and other commands to make a
43 # user-friendly and stable text. We can easily prepare the expect text
44 # without having to worry about future changes of the commit ID and spaces
46 make_user_friendly_and_stable_output
() {
51 -e "s/$A/<COMMIT-A>/g" \
52 -e "s/$B/<COMMIT-B>/g" \
53 -e "s/$ZERO_OID/<ZERO-OID>/g" \
54 -e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \
55 -e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g" \
56 -e "s#To $URL_PREFIX/upstream.git#To <URL/of/upstream.git>#"
59 setup_upstream_and_workbench
() {
60 # Upstream after setup : master(B) foo(A) bar(A) baz(A)
61 # Workbench after setup : master(A)
62 test_expect_success
"setup upstream repository and workbench" '
63 rm -rf upstream.git workbench &&
64 git init --bare upstream.git &&
66 create_commits_in workbench A B &&
69 # Try to make a stable fixed width for abbreviated commit ID,
70 # this fixed-width oid will be replaced with "<OID>".
71 git config core.abbrev 7 &&
72 git remote add origin ../upstream.git &&
73 git update-ref refs/heads/master $A &&
75 $B:refs/heads/master \
80 git -C "workbench" config advice.pushUpdateRejected false &&
85 run_git_push_porcelain_output_test
() {
88 PROTOCOL
="HTTP protocol"
89 URL_PREFIX
="http://.*"
92 PROTOCOL
="builtin protocol"
97 # Refs of upstream : master(B) foo(A) bar(A) baz(A)
98 # Refs of workbench: master(A) baz(A) next(A)
99 # git-push : master(A) NULL (B) baz(A) next(A)
100 test_expect_success
"porcelain output of successful git-push ($PROTOCOL)" '
103 git update-ref refs/heads/master $A &&
104 git update-ref refs/heads/baz $A &&
105 git update-ref refs/heads/next $A &&
106 git push --porcelain --force origin \
113 make_user_friendly_and_stable_output <out >actual &&
114 cat >expect <<-EOF &&
115 To <URL/of/upstream.git>
116 = refs/heads/baz:refs/heads/baz [up to date]
117 <COMMIT-B>:refs/heads/bar <OID-A>..<OID-B>
118 - :refs/heads/foo [deleted]
119 + refs/heads/master:refs/heads/master <OID-B>...<OID-A> (forced update)
120 * refs/heads/next:refs/heads/next [new branch]
123 test_cmp expect actual &&
125 git -C "$upstream" show-ref >out &&
126 make_user_friendly_and_stable_output <out >actual &&
127 cat >expect <<-EOF &&
128 <COMMIT-B> refs/heads/bar
129 <COMMIT-A> refs/heads/baz
130 <COMMIT-A> refs/heads/master
131 <COMMIT-A> refs/heads/next
133 test_cmp expect actual
136 # Refs of upstream : master(A) bar(B) baz(A) next(A)
137 # Refs of workbench: master(B) bar(A) baz(A) next(A)
138 # git-push : master(B) bar(A) NULL next(A)
139 test_expect_success
"atomic push failed ($PROTOCOL)" '
142 git update-ref refs/heads/master $B &&
143 git update-ref refs/heads/bar $A &&
144 test_must_fail git push --atomic --porcelain origin \
150 make_user_friendly_and_stable_output <out >actual &&
151 cat >expect <<-EOF &&
152 To <URL/of/upstream.git>
153 ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
154 ! (delete):refs/heads/baz [rejected] (atomic push failed)
155 ! refs/heads/master:refs/heads/master [rejected] (atomic push failed)
156 ! refs/heads/next:refs/heads/next [rejected] (atomic push failed)
159 test_cmp expect actual &&
161 git -C "$upstream" show-ref >out &&
162 make_user_friendly_and_stable_output <out >actual &&
163 cat >expect <<-EOF &&
164 <COMMIT-B> refs/heads/bar
165 <COMMIT-A> refs/heads/baz
166 <COMMIT-A> refs/heads/master
167 <COMMIT-A> refs/heads/next
169 test_cmp expect actual
172 test_expect_success
"prepare pre-receive hook ($PROTOCOL)" '
173 write_script "$upstream/hooks/pre-receive" <<-EOF
178 # Refs of upstream : master(A) bar(B) baz(A) next(A)
179 # Refs of workbench: master(B) bar(A) baz(A) next(A)
180 # git-push : master(B) bar(A) NULL next(A)
181 test_expect_success
"pre-receive hook declined ($PROTOCOL)" '
184 git update-ref refs/heads/master $B &&
185 git update-ref refs/heads/bar $A &&
186 test_must_fail git push --porcelain --force origin \
192 make_user_friendly_and_stable_output <out >actual &&
193 cat >expect <<-EOF &&
194 To <URL/of/upstream.git>
195 = refs/heads/next:refs/heads/next [up to date]
196 ! refs/heads/bar:refs/heads/bar [remote rejected] (pre-receive hook declined)
197 ! :refs/heads/baz [remote rejected] (pre-receive hook declined)
198 ! refs/heads/master:refs/heads/master [remote rejected] (pre-receive hook declined)
201 test_cmp expect actual &&
203 git -C "$upstream" show-ref >out &&
204 make_user_friendly_and_stable_output <out >actual &&
205 cat >expect <<-EOF &&
206 <COMMIT-B> refs/heads/bar
207 <COMMIT-A> refs/heads/baz
208 <COMMIT-A> refs/heads/master
209 <COMMIT-A> refs/heads/next
211 test_cmp expect actual
214 test_expect_success
"remove pre-receive hook ($PROTOCOL)" '
215 rm "$upstream/hooks/pre-receive"
218 # Refs of upstream : master(A) bar(B) baz(A) next(A)
219 # Refs of workbench: master(B) bar(A) baz(A) next(A)
220 # git-push : master(B) bar(A) NULL next(A)
221 test_expect_success
"non-fastforward push ($PROTOCOL)" '
224 test_must_fail git push --porcelain origin \
230 make_user_friendly_and_stable_output <out >actual &&
231 cat >expect <<-EOF &&
232 To <URL/of/upstream.git>
233 = refs/heads/next:refs/heads/next [up to date]
234 - :refs/heads/baz [deleted]
235 refs/heads/master:refs/heads/master <OID-A>..<OID-B>
236 ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
239 test_cmp expect actual &&
241 git -C "$upstream" show-ref >out &&
242 make_user_friendly_and_stable_output <out >actual &&
243 cat >expect <<-EOF &&
244 <COMMIT-B> refs/heads/bar
245 <COMMIT-B> refs/heads/master
246 <COMMIT-A> refs/heads/next
248 test_cmp expect actual
252 # Initialize the upstream repository and local workbench.
253 setup_upstream_and_workbench
255 # Run git-push porcelain test on builtin protocol
256 run_git_push_porcelain_output_test
file
259 .
"$TEST_DIRECTORY"/lib-gpg.sh
260 .
"$TEST_DIRECTORY"/lib-httpd.sh
261 .
"$TEST_DIRECTORY"/lib-terminal.sh
264 # Re-initialize the upstream repository and local workbench.
265 setup_upstream_and_workbench
267 test_expect_success
"setup for http" '
268 git -C upstream.git config http.receivepack true &&
269 upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
270 mv upstream.git "$upstream" &&
272 git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git
277 # Run git-push porcelain test on HTTP protocol
278 run_git_push_porcelain_output_test http