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
() {
17 repo
="$1" && test -d "$repo" ||
18 error
"Repository $repo does not exist."
24 test_commit
-C "$repo" --no-tag "$name" &&
25 eval $name=$
(git
-C "$repo" rev-parse HEAD
)
31 suffix
=${oid#???????} &&
41 # Format the output of git-push, git-show-ref and other commands to make a
42 # user-friendly and stable text. We can easily prepare the expect text
43 # without having to worry about future changes of the commit ID and spaces
45 make_user_friendly_and_stable_output
() {
47 -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \
48 -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \
49 -e "s/$ZERO_OID/<ZERO-OID>/g" \
50 -e "s#To $URL_PREFIX/upstream.git#To <URL/of/upstream.git>#"
53 format_and_save_expect
() {
54 sed -e 's/^> //' -e 's/Z$//' >expect
57 setup_upstream_and_workbench
() {
58 # Upstream after setup : main(B) foo(A) bar(A) baz(A)
59 # Workbench after setup : main(A)
60 test_expect_success
"setup upstream repository and workbench" '
61 rm -rf upstream.git workbench &&
62 git init --bare upstream.git &&
64 create_commits_in workbench A B &&
67 # Try to make a stable fixed width for abbreviated commit ID,
68 # this fixed-width oid will be replaced with "<OID>".
69 git config core.abbrev 7 &&
70 git remote add origin ../upstream.git &&
71 git update-ref refs/heads/main $A &&
78 git -C "workbench" config advice.pushUpdateRejected false &&
83 run_git_push_porcelain_output_test
() {
86 PROTOCOL
="HTTP protocol"
87 URL_PREFIX
="http://.*"
90 PROTOCOL
="builtin protocol"
95 # Refs of upstream : main(B) foo(A) bar(A) baz(A)
96 # Refs of workbench: main(A) baz(A) next(A)
97 # git-push : main(A) NULL (B) baz(A) next(A)
98 test_expect_success
"porcelain output of successful git-push ($PROTOCOL)" '
101 git update-ref refs/heads/main $A &&
102 git update-ref refs/heads/baz $A &&
103 git update-ref refs/heads/next $A &&
104 git push --porcelain --force origin \
111 make_user_friendly_and_stable_output <out >actual &&
112 format_and_save_expect <<-EOF &&
113 > To <URL/of/upstream.git>
114 > = refs/heads/baz:refs/heads/baz [up to date]
115 > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B>
116 > - :refs/heads/foo [deleted]
117 > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update)
118 > * refs/heads/next:refs/heads/next [new branch]
121 test_cmp expect actual &&
123 git -C "$upstream" show-ref >out &&
124 make_user_friendly_and_stable_output <out >actual &&
125 cat >expect <<-EOF &&
126 <COMMIT-B> refs/heads/bar
127 <COMMIT-A> refs/heads/baz
128 <COMMIT-A> refs/heads/main
129 <COMMIT-A> refs/heads/next
131 test_cmp expect actual
134 # Refs of upstream : main(A) bar(B) baz(A) next(A)
135 # Refs of workbench: main(B) bar(A) baz(A) next(A)
136 # git-push : main(B) bar(A) NULL next(A)
137 test_expect_success
"atomic push failed ($PROTOCOL)" '
140 git update-ref refs/heads/main $B &&
141 git update-ref refs/heads/bar $A &&
142 test_must_fail git push --atomic --porcelain origin \
148 make_user_friendly_and_stable_output <out >actual &&
149 format_and_save_expect <<-EOF &&
150 To <URL/of/upstream.git>
151 > = refs/heads/next:refs/heads/next [up to date]
152 > ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
153 > ! (delete):refs/heads/baz [rejected] (atomic push failed)
154 > ! refs/heads/main:refs/heads/main [rejected] (atomic push failed)
157 test_cmp expect actual &&
159 git -C "$upstream" show-ref >out &&
160 make_user_friendly_and_stable_output <out >actual &&
161 cat >expect <<-EOF &&
162 <COMMIT-B> refs/heads/bar
163 <COMMIT-A> refs/heads/baz
164 <COMMIT-A> refs/heads/main
165 <COMMIT-A> refs/heads/next
167 test_cmp expect actual
170 test_expect_success
"prepare pre-receive hook ($PROTOCOL)" '
171 write_script "$upstream/hooks/pre-receive" <<-EOF
176 # Refs of upstream : main(A) bar(B) baz(A) next(A)
177 # Refs of workbench: main(B) bar(A) baz(A) next(A)
178 # git-push : main(B) bar(A) NULL next(A)
179 test_expect_success
"pre-receive hook declined ($PROTOCOL)" '
182 git update-ref refs/heads/main $B &&
183 git update-ref refs/heads/bar $A &&
184 test_must_fail git push --porcelain --force origin \
190 make_user_friendly_and_stable_output <out >actual &&
191 format_and_save_expect <<-EOF &&
192 To <URL/of/upstream.git>
193 > = refs/heads/next:refs/heads/next [up to date]
194 > ! refs/heads/bar:refs/heads/bar [remote rejected] (pre-receive hook declined)
195 > ! :refs/heads/baz [remote rejected] (pre-receive hook declined)
196 > ! refs/heads/main:refs/heads/main [remote rejected] (pre-receive hook declined)
199 test_cmp expect actual &&
201 git -C "$upstream" show-ref >out &&
202 make_user_friendly_and_stable_output <out >actual &&
203 cat >expect <<-EOF &&
204 <COMMIT-B> refs/heads/bar
205 <COMMIT-A> refs/heads/baz
206 <COMMIT-A> refs/heads/main
207 <COMMIT-A> refs/heads/next
209 test_cmp expect actual
212 test_expect_success
"remove pre-receive hook ($PROTOCOL)" '
213 rm "$upstream/hooks/pre-receive"
216 # Refs of upstream : main(A) bar(B) baz(A) next(A)
217 # Refs of workbench: main(B) bar(A) baz(A) next(A)
218 # git-push : main(B) bar(A) NULL next(A)
219 test_expect_success
"non-fastforward push ($PROTOCOL)" '
222 test_must_fail git push --porcelain origin \
228 make_user_friendly_and_stable_output <out >actual &&
229 format_and_save_expect <<-EOF &&
230 To <URL/of/upstream.git>
231 > = refs/heads/next:refs/heads/next [up to date]
232 > - :refs/heads/baz [deleted]
233 > refs/heads/main:refs/heads/main <COMMIT-A>..<COMMIT-B>
234 > ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward)
237 test_cmp expect actual &&
239 git -C "$upstream" show-ref >out &&
240 make_user_friendly_and_stable_output <out >actual &&
241 cat >expect <<-EOF &&
242 <COMMIT-B> refs/heads/bar
243 <COMMIT-B> refs/heads/main
244 <COMMIT-A> refs/heads/next
246 test_cmp expect actual
250 # Initialize the upstream repository and local workbench.
251 setup_upstream_and_workbench
253 # Run git-push porcelain test on builtin protocol
254 run_git_push_porcelain_output_test
file
257 .
"$TEST_DIRECTORY"/lib-gpg.sh
258 .
"$TEST_DIRECTORY"/lib-httpd.sh
259 .
"$TEST_DIRECTORY"/lib-terminal.sh
262 # Re-initialize the upstream repository and local workbench.
263 setup_upstream_and_workbench
265 test_expect_success
"setup for http" '
266 git -C upstream.git config http.receivepack true &&
267 upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
268 mv upstream.git "$upstream" &&
270 git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git
275 # Run git-push porcelain test on HTTP protocol
276 run_git_push_porcelain_output_test http