diff --git a/contrib/adc/hub.mkd b/contrib/adc/hub.mkd new file mode 100644 index 0000000..a45e8af --- /dev/null +++ b/contrib/adc/hub.mkd @@ -0,0 +1,182 @@ +# the 'hub' ADC + +In this document: + + * a home grown 'hub' for git repos + * general syntax + * Bob's commands + * Alice's "just looking" commands + * Alice's "action" commands + * what next? + * note to the admin: configuration variables + + + +### a home grown 'hub' for git repos + +This ADC (admin-defined command) helps collaboration among repos. The name is +in honor of github, which is the primary host for gitolite itself. + +[Note that github is a web-based service, and does a lot more, like comments, +code reviews, etc., none of which are possible here. We're only talking about +some basic stuff to make the most common operations easier. In particular, +this system is not a replacement for normal project communications like +email!] + +**Conventions used**: all through the following description, we will assume +that **Alice** has a repo **parent**, **Bob** has a fork of parent called +**child**, and he is asking Alice to pull a branch he made called **b1** from +child to parent. + +In plain git (without using github or similar), the pull request process +starts with an email from Bob to Alice, followed by Alice running a `git fetch + b1` (optionally preceded by a `git remote add` for convenience of +long term use). Until this happens she can't see much detail about the +commits to be pulled. + +**What this ADC does** is (a) collect all the pull requests she needs to look +at in one place, and (b) allow her to examine the changes with any combination +of `git log` and `git diff` options *without having to fetch the content +first*, and (c) act as a trusted intermediary to allow Alice to fetch *just +one branch* from Bob even if she does not have any access to Bob's repository! + +In a situation where there may be lots of requests, being able to take a quick +look at them (and possibly reject some), without having to pull down anything +at all, could be very useful. + +Once past that level, she could get the changes down to her workstation using +`git fetch` as normal. With this ADC, however, she has another alternative: +get them over to `parent` (her repo) on the same gitolite server, then later +do a normal `git fetch [origin]` to get it to her workstation. This has the +added advantage that other people, who may be watching her repo but not Bob's, +now get to see what Bob sent her and send comments etc. + + + +### general syntax + +The general syntax is + + ssh git@server hub + + + +#### Bob's commands + +The following commands do not cause a fetch, and should be quite fast: + + * Bob sends a pull request for branch b1 to repo parent. Notice he does not + mention Alice by name. This command expects a message to be piped/typed + in via STDIN [this message is meant to be transient and is not stored long + term; use email for more "permanent" communications]. + + echo "hi Alice, please pull" | request-pull child b1 [parent] + + If `child` was created by a recent version of the 'fork' ADC (or the KDE + 'clone' ADC), which records the name of the parent repo on a fork, and it + is *that* repo to which Bob wishes to send the pull request, the third + argument is optional. + + * Bob lists the status (fetched/rejected/pending) of pull requests he has + made from his repo child to repo parent. (Note we don't say "accepted" but + "fetched"; see later for why): + + request-status child [parent] + + The second argument is optional the same way as the 3rd argument in the + previous command. + + + +#### Alice's "just looking" commands + + * Alice lists requests waiting for her to check and possibly pull into + parent. For each waiting pull request, she will see a serial number, the + originating repo name (child, in our example), the requestor (Bob, here), + and the branch/tag-name (b1) being pulled: + + list-requests parent + + * Alice views request # 1 waiting to be pulled into parent. Shows the same + details as above for that request, followed by the message that Bob typed + in when he ran `request-pull`: + + view-request parent 1 + + * Alice views the log of the branch she is being asked to pull. Note that + this does NOT involve a fetch, so it will be pretty fast. The log starts + from b1, and stops at a SHA that represents any of the branches in parent. + Alice can use any git-log options she wants to; for instance `--graph`, + `--decorate`, `--boundary`, etc., could be quite useful. However, she + can't use any GUI; it has to be 'git log': + + view-log parent 1 + + Notice that the repo name Alice supplies is still her own, although the + log comes from the child repo that Bob wants Alice to pull from. It's + best if you think of this as "view the commits from pull request #1 in + 'parent'". + + * Alice views the diff between arbitrary commits on child: + + view-diff parent 1 + + Again, she mentions *her* reponame but the diff's come from `child`. Also + note that, due to restrictions on what characters are allowed in arguments + to ADCs, you probably can't do things like `pu^` or `master~3`, and have + to use SHAs instead. + + + +#### Alice's "action" commands + + * Alice doesn't like what she sees and decides to reject it. This command + expects some text on STDIN as the rejection message: + + echo "hi Bob, your patch needs work; see email" | reject parent 1 + +The following commands will actually fetch from child into parent, and may take +time if the changes are large. However all this is on the server so it does +not involve network traffic: + + * Alice likes what she sees so far and wants to fetch the branch Bob is + asking her to pull. Note that we are intentionally not using the word + "accept", because this command does not (and cannot, since it is running + on a bare repo on the server) do a pull. What it does is it fetches into + a branch whose name will be `requests/child/b1`. + + Note that when multiple requests from the same repo (child) for the same + branch (b1) happen, each "fetch" overwrites the branch. This allows Bob + to continually refine the branch he is requesting for a pull based on + (presumably emailed) comments from Alice. In a way, this is a "remote + tracking branch", just like `refs/remotes/origin/b1`. + + fetch parent 1 + + + +### what next? + +At this point, you're done with the `hub` ADC. However, all this is on the +bare `parent.git` on the server, and nothing has hit Alice's workstation yet! +Alice will still have to run a fetch or a pull on her workstation if she wants +to check the code in detail, use a tool like gitk, and especially to +compile/test it. *Then* she decides whether to accept or reject the request, +which will have to be communicated via email, of course; see the second para +of this document ;-) + +Finally, note that Alice does not actually need to use the `fetch` subcommand. +She can do the traditional thing and fetch Bob's repo/branch directly to her +*workstation*. + + + +### note to the admin: configuration variables + +There are 2 configuration variables. `BASE_FETCH_URL` should be set to a +simple "read" URL (so it doesn't even have to be ssh) that almost anyone using +this server can use. It's only used in producing the `git fetch` command +mentioned just above. + +`GL_FORKED_FROM` is set to `gl-forked-from` by default, but if your initials +are `JM` you can set it to `kde-cloned-from` to save time and trouble ;-) diff --git a/t/t67-hub b/t/t67-hub new file mode 100644 index 0000000..75d6ffd --- /dev/null +++ b/t/t67-hub @@ -0,0 +1,156 @@ +# vim: syn=sh: +for bc in 0 1 +do + cd $TESTDIR + $TESTDIR/rollback || die "rollback failed" + editrc GL_BIG_CONFIG $bc + editrc GL_WILDREPOS 1 + + rm -rf /tmp/glt-adc + mkdir /tmp/glt-adc || die "mkdir /tmp/glt-adc failed" + cp ../contrib/adc/* /tmp/glt-adc + echo "\$GL_ADC_PATH = '/tmp/glt-adc';" | addrc + runremote rm -f .gitolite.down + + # ---------- + + name "INTERNAL" + echo " + @alice = u1 + @bob = u2 + @parent = r1 + @child = r2 + + repo @parent + RW+ = @alice + RW = tester + R = @bob + + @children = child/CREATOR/..* + repo @children + C = @all + RW+ = CREATOR + " | ugc + expect_push_ok "master -> master" + + name "setup: parent gets some branches" + cd ~/td + runlocal git clone u1:r1 + cd r1 + mdc base1; mdc base2; mdc base3 + runlocal git branch p3 + runlocal git branch p2 + runlocal git branch p1 + mdc p1a; mdc p1b; mdc p1c + runlocal git checkout p2 + mdc p2a; mdc p2b; mdc p2c + runlocal git checkout p3 + mdc p3a; mdc p3b; mdc p3c + runlocal git push origin --all + expect To u1:r1 + expect "\* \[new branch\] master -> master" + expect "\* \[new branch\] p1 -> p1" + expect "\* \[new branch\] p2 -> p2" + expect "\* \[new branch\] p3 -> p3" + + name "setup: child is cloned and adds b1 and b2" + cd ~/td + runlocal ssh u2 fork r1 child/u2/myr1 + runremote ls -al repositories/child/u2/myr1.git/gl-forked-from + expect "gitolite-test gitolite-test 3 .* repositories/child/u2/myr1.git/gl-forked-from" + runremote cat repositories/child/u2/myr1.git/gl-forked-from + expect r1 + runlocal git clone u2:child/u2/myr1 + cd myr1 + runlocal git checkout -b b1 origin/p1 + mdc c1 + runlocal git checkout -b b2 origin/p2 + mdc d1; mdc d2 + runlocal git checkout -b b3 origin/p3 + mdc e1; mdc e2; mdc e3 + runlocal git push origin b1 b2 b3 + expect To u2:child/u2/myr1 + expect "\* \[new branch\] b1 -> b1" + expect "\* \[new branch\] b2 -> b2" + expect "\* \[new branch\] b3 -> b3" + + name "bob sends in a few pull requests" + printf "hello\nthere" | runlocal ssh u2 hub request-pull child/u2/myr1 b1 + notexpect . + printf "hi\nthere" | runlocal ssh u2 hub request-pull child/u2/myr1 b2 + notexpect . + printf "hello\nagain" | runlocal ssh u2 hub request-pull child/u2/myr1 b3 + notexpect . + + name "bob checks his pending requests" + runlocal ssh u2 hub request-status child/u2/myr1 + expect "1 child/u2/myr1 (u2) b1 pending" + expect "2 child/u2/myr1 (u2) b2 pending" + expect "3 child/u2/myr1 (u2) b3 pending" + + name "alice checks her pull requests" + runlocal ssh u1 hub list-requests r1 + expect "1 child/u2/myr1 (u2) b1 pending" + expect "2 child/u2/myr1 (u2) b2 pending" + expect "3 child/u2/myr1 (u2) b3 pending" + + name "alice views request 1" + runlocal ssh u1 hub view-request r1 1 + expect "1 child/u2/myr1 (u2) b1 pending" + expect ^hello + expect ^there + + name "alice views log and diffs" + runlocal ssh u1 hub view-log r1 1 + expect "setup: child is cloned and adds b1 and b2" + expect commit + wc < ~/1 > ~/2; > ~/1 + expect "5 22 178" + + runlocal ssh u1 hub view-log r1 3 --oneline + expect "setup: child is cloned and adds b1 and b2" + notexpect commit + diffargs=`tac ~/1 | cut -f1 -d' ' | sed -n -e1p -e3p` + wc < ~/1 > ~/2; > ~/1 + expect "3 30 150" + + runlocal ssh u1 hub view-log r1 2 b1 + expect "fatal: ambiguous argument 'b1': unknown revision or path not in the working tree." + + runlocal ssh u1 hub view-diff r1 3 $diffargs + expect "diff.*e2" + expect "diff.*e3" + expect "new file mode" + + name "alice tries to view a SHA she shouldnt" + echo > ~/1 + echo > ~/2 + runlocal ssh u1 hub view-diff r1 2 $diffargs + notexpect "diff.*e2" + notexpect "diff.*e3" + notexpect "new file mode" + expect "invalid SHA:" + + name "alice rejects 2, accepts 3" + echo captain was sober today | runlocal ssh u1 hub reject r1 2 + notexpect . + echo | runlocal ssh u1 hub fetch r1 3 + expect "user u2 asked you to" + expect "git fetch git://gl.example.com/child/u2/myr1 b3" + expect "From /home/gitolite-test/repositories/child/u2/myr1" + expect "\* \[new branch\] b3 -> requests/child/b3" + + name "bob checks his pending requests" + runlocal ssh u2 hub request-status child/u2/myr1 + expect "1 child/u2/myr1 (u2) b1 pending" + expect "2 child/u2/myr1 (u2) b2 rejected" + expect "3 child/u2/myr1 (u2) b3 fetched" + + name "alice checks her pull requests" + runlocal ssh u1 hub list-requests r1 + expect "1 child/u2/myr1 (u2) b1 pending" + expect "2 child/u2/myr1 (u2) b2 rejected" + expect "3 child/u2/myr1 (u2) b3 fetched" + + name "INTERNAL" +done