| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='pushing to a repository using the atomic push option' |
| 4 | |
| 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
| 6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | |
| 10 | mk_repo_pair () { |
| 11 | rm -rf workbench upstream && |
| 12 | test_create_repo upstream && |
| 13 | test_create_repo workbench && |
| 14 | ( |
| 15 | cd upstream && |
| 16 | git config receive.denyCurrentBranch warn |
| 17 | ) && |
| 18 | ( |
| 19 | cd workbench && |
| 20 | git remote add up ../upstream |
| 21 | ) |
| 22 | } |
| 23 | |
| 24 | # Compare the ref ($1) in upstream with a ref value from workbench ($2) |
| 25 | # i.e. test_refs second HEAD@{2} |
| 26 | test_refs () { |
| 27 | test $# = 2 && |
| 28 | git -C upstream rev-parse --verify "$1" >expect && |
| 29 | git -C workbench rev-parse --verify "$2" >actual && |
| 30 | test_cmp expect actual |
| 31 | } |
| 32 | |
| 33 | fmt_status_report () { |
| 34 | sed -n \ |
| 35 | -e "/^To / { s/ */ /g; p; }" \ |
| 36 | -e "/^ ! / { s/ */ /g; p; }" |
| 37 | } |
| 38 | |
| 39 | test_expect_success 'atomic push works for a single branch' ' |
| 40 | mk_repo_pair && |
| 41 | ( |
| 42 | cd workbench && |
| 43 | test_commit one && |
| 44 | git push --mirror up && |
| 45 | test_commit two && |
| 46 | git push --atomic up main |
| 47 | ) && |
| 48 | test_refs main main |
| 49 | ' |
| 50 | |
| 51 | test_expect_success 'atomic push works for two branches' ' |
| 52 | mk_repo_pair && |
| 53 | ( |
| 54 | cd workbench && |
| 55 | test_commit one && |
| 56 | git branch second && |
| 57 | git push --mirror up && |
| 58 | test_commit two && |
| 59 | git checkout second && |
| 60 | test_commit three && |
| 61 | git push --atomic up main second |
| 62 | ) && |
| 63 | test_refs main main && |
| 64 | test_refs second second |
| 65 | ' |
| 66 | |
| 67 | test_expect_success 'atomic push works in combination with --mirror' ' |
| 68 | mk_repo_pair && |
| 69 | ( |
| 70 | cd workbench && |
| 71 | test_commit one && |
| 72 | git checkout -b second && |
| 73 | test_commit two && |
| 74 | git push --atomic --mirror up |
| 75 | ) && |
| 76 | test_refs main main && |
| 77 | test_refs second second |
| 78 | ' |
| 79 | |
| 80 | test_expect_success 'atomic push works in combination with --force' ' |
| 81 | mk_repo_pair && |
| 82 | ( |
| 83 | cd workbench && |
| 84 | test_commit one && |
| 85 | git branch second main && |
| 86 | test_commit two_a && |
| 87 | git checkout second && |
| 88 | test_commit two_b && |
| 89 | test_commit three_b && |
| 90 | test_commit four && |
| 91 | git push --mirror up && |
| 92 | # The actual test is below |
| 93 | git checkout main && |
| 94 | test_commit three_a && |
| 95 | git checkout second && |
| 96 | git reset --hard HEAD^ && |
| 97 | git push --force --atomic up main second |
| 98 | ) && |
| 99 | test_refs main main && |
| 100 | test_refs second second |
| 101 | ' |
| 102 | |
| 103 | # set up two branches where main can be pushed but second can not |
| 104 | # (non-fast-forward). Since second can not be pushed the whole operation |
| 105 | # will fail and leave main untouched. |
| 106 | test_expect_success 'atomic push fails if one branch fails' ' |
| 107 | mk_repo_pair && |
| 108 | ( |
| 109 | cd workbench && |
| 110 | test_commit one && |
| 111 | git checkout -b second main && |
| 112 | test_commit two && |
| 113 | test_commit three && |
| 114 | test_commit four && |
| 115 | git push --mirror up && |
| 116 | git reset --hard HEAD~2 && |
| 117 | test_commit five && |
| 118 | git checkout main && |
| 119 | test_commit six && |
| 120 | test_must_fail git push --atomic --all up >output-all 2>&1 && |
| 121 | # --all and --branches have the same behavior when be combined with --atomic |
| 122 | test_must_fail git push --atomic --branches up >output-branches 2>&1 && |
| 123 | test_cmp output-all output-branches |
| 124 | ) && |
| 125 | test_refs main HEAD@{7} && |
| 126 | test_refs second HEAD@{4} |
| 127 | ' |
| 128 | |
| 129 | test_expect_success 'atomic push fails if one tag fails remotely' ' |
| 130 | # prepare the repo |
| 131 | mk_repo_pair && |
| 132 | ( |
| 133 | cd workbench && |
| 134 | test_commit one && |
| 135 | git checkout -b second main && |
| 136 | test_commit two && |
| 137 | git push --mirror up |
| 138 | ) && |
| 139 | # a third party modifies the server side: |
| 140 | ( |
| 141 | cd upstream && |
| 142 | git checkout second && |
| 143 | git tag test_tag second |
| 144 | ) && |
| 145 | # see if we can now push both branches. |
| 146 | ( |
| 147 | cd workbench && |
| 148 | git checkout main && |
| 149 | test_commit three && |
| 150 | git checkout second && |
| 151 | test_commit four && |
| 152 | git tag test_tag && |
| 153 | test_must_fail git push --tags --atomic up main second |
| 154 | ) && |
| 155 | test_refs main HEAD@{3} && |
| 156 | test_refs second HEAD@{1} |
| 157 | ' |
| 158 | |
| 159 | test_expect_success 'atomic push obeys update hook preventing a branch to be pushed' ' |
| 160 | mk_repo_pair && |
| 161 | ( |
| 162 | cd workbench && |
| 163 | test_commit one && |
| 164 | git checkout -b second main && |
| 165 | test_commit two && |
| 166 | git push --mirror up |
| 167 | ) && |
| 168 | test_hook -C upstream update <<-\EOF && |
| 169 | # only allow update to main from now on |
| 170 | test "$1" = "refs/heads/main" |
| 171 | EOF |
| 172 | ( |
| 173 | cd workbench && |
| 174 | git checkout main && |
| 175 | test_commit three && |
| 176 | git checkout second && |
| 177 | test_commit four && |
| 178 | test_must_fail git push --atomic up main second |
| 179 | ) && |
| 180 | test_refs main HEAD@{3} && |
| 181 | test_refs second HEAD@{1} |
| 182 | ' |
| 183 | |
| 184 | test_expect_success 'atomic push is not advertised if configured' ' |
| 185 | mk_repo_pair && |
| 186 | ( |
| 187 | cd upstream && |
| 188 | git config receive.advertiseatomic 0 |
| 189 | ) && |
| 190 | ( |
| 191 | cd workbench && |
| 192 | test_commit one && |
| 193 | git push --mirror up && |
| 194 | test_commit two && |
| 195 | test_must_fail git push --atomic up main |
| 196 | ) && |
| 197 | test_refs main HEAD@{1} |
| 198 | ' |
| 199 | |
| 200 | # References in upstream : main(1) one(1) foo(1) |
| 201 | # References in workbench: main(2) foo(1) two(2) bar(2) |
| 202 | # Atomic push : main(2) two(2) bar(2) |
| 203 | test_expect_success 'atomic push reports (reject by update hook)' ' |
| 204 | mk_repo_pair && |
| 205 | ( |
| 206 | cd workbench && |
| 207 | test_commit one && |
| 208 | git branch foo && |
| 209 | git push up main one foo && |
| 210 | git tag -d one |
| 211 | ) && |
| 212 | ( |
| 213 | mkdir -p upstream/.git/hooks && |
| 214 | cat >upstream/.git/hooks/update <<-EOF && |
| 215 | #!/bin/sh |
| 216 | |
| 217 | if test "\$1" = "refs/heads/bar" |
| 218 | then |
| 219 | echo >&2 "Pusing to branch bar is prohibited" |
| 220 | exit 1 |
| 221 | fi |
| 222 | EOF |
| 223 | chmod a+x upstream/.git/hooks/update |
| 224 | ) && |
| 225 | ( |
| 226 | cd workbench && |
| 227 | test_commit two && |
| 228 | git branch bar |
| 229 | ) && |
| 230 | test_must_fail git -C workbench \ |
| 231 | push --atomic up main two bar >out 2>&1 && |
| 232 | fmt_status_report <out >actual && |
| 233 | cat >expect <<-EOF && |
| 234 | To ../upstream |
| 235 | ! [remote rejected] main -> main (atomic push failure) |
| 236 | ! [remote rejected] two -> two (atomic push failure) |
| 237 | ! [remote rejected] bar -> bar (hook declined) |
| 238 | EOF |
| 239 | test_cmp expect actual |
| 240 | ' |
| 241 | |
| 242 | # References in upstream : main(1) one(1) foo(1) |
| 243 | # References in workbench: main(2) foo(1) two(2) bar(2) |
| 244 | test_expect_success 'atomic push reports (mirror, but reject by update hook)' ' |
| 245 | ( |
| 246 | cd workbench && |
| 247 | git remote remove up && |
| 248 | git remote add up ../upstream |
| 249 | ) && |
| 250 | test_must_fail git -C workbench \ |
| 251 | push --atomic --mirror up >out 2>&1 && |
| 252 | fmt_status_report <out >actual && |
| 253 | cat >expect <<-EOF && |
| 254 | To ../upstream |
| 255 | ! [remote rejected] main -> main (atomic push failure) |
| 256 | ! [remote rejected] one (atomic push failure) |
| 257 | ! [remote rejected] bar -> bar (hook declined) |
| 258 | ! [remote rejected] two -> two (atomic push failure) |
| 259 | EOF |
| 260 | test_cmp expect actual |
| 261 | ' |
| 262 | |
| 263 | # References in upstream : main(2) one(1) foo(1) |
| 264 | # References in workbench: main(1) foo(1) two(2) bar(2) |
| 265 | test_expect_success 'atomic push reports (reject by non-ff)' ' |
| 266 | rm upstream/.git/hooks/update && |
| 267 | ( |
| 268 | cd workbench && |
| 269 | git push up main && |
| 270 | git reset --hard HEAD^ |
| 271 | ) && |
| 272 | test_must_fail git -C workbench \ |
| 273 | push --atomic up main foo bar >out 2>&1 && |
| 274 | fmt_status_report <out >actual && |
| 275 | cat >expect <<-EOF && |
| 276 | To ../upstream |
| 277 | ! [rejected] main -> main (non-fast-forward) |
| 278 | ! [rejected] bar -> bar (atomic push failed) |
| 279 | EOF |
| 280 | test_cmp expect actual |
| 281 | ' |
| 282 | |
| 283 | test_expect_success 'atomic push reports exit code failure' ' |
| 284 | write_script receive-pack-wrapper <<-\EOF && |
| 285 | git-receive-pack "$@" |
| 286 | exit 1 |
| 287 | EOF |
| 288 | test_must_fail git -C workbench push --atomic \ |
| 289 | --receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \ |
| 290 | up HEAD:refs/heads/no-conflict 2>err && |
| 291 | cat >expect <<-EOF && |
| 292 | To ../upstream |
| 293 | * [new branch] HEAD -> no-conflict |
| 294 | error: failed to push some refs to ${SQ}../upstream${SQ} |
| 295 | EOF |
| 296 | test_cmp expect err |
| 297 | ' |
| 298 | |
| 299 | test_expect_success 'atomic push reports exit code failure with porcelain' ' |
| 300 | write_script receive-pack-wrapper <<-\EOF && |
| 301 | git-receive-pack "$@" |
| 302 | exit 1 |
| 303 | EOF |
| 304 | test_must_fail git -C workbench push --atomic --porcelain \ |
| 305 | --receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \ |
| 306 | up HEAD:refs/heads/no-conflict-porcelain 2>err && |
| 307 | cat >expect <<-EOF && |
| 308 | error: failed to push some refs to ${SQ}../upstream${SQ} |
| 309 | EOF |
| 310 | test_cmp expect err |
| 311 | ' |
| 312 | |
| 313 | test_done |