'hub' ADC doc and rudimentary test script

This commit is contained in:
Sitaram Chamarty 2011-03-02 14:47:05 +05:30
parent 49e64a4f11
commit 6d3c2fbcef
2 changed files with 338 additions and 0 deletions

182
contrib/adc/hub.mkd Normal file
View file

@ -0,0 +1,182 @@
# the 'hub' ADC
In this document:
* <a href="#_a_home_grown_hub_for_git_repos">a home grown 'hub' for git repos</a>
* <a href="#_general_syntax">general syntax</a>
* <a href="#_Bob_s_commands">Bob's commands</a>
* <a href="#_Alice_s_just_looking_commands">Alice's "just looking" commands</a>
* <a href="#_Alice_s_action_commands">Alice's "action" commands</a>
* <a href="#_what_next_">what next?</a>
* <a href="#_note_to_the_admin_configuration_variables">note to the admin: configuration variables</a>
<a name="_a_home_grown_hub_for_git_repos"></a>
### 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
<Bob's URL> 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.
<a name="_general_syntax"></a>
### general syntax
The general syntax is
ssh git@server hub <hub-command> <args>
<a name="_Bob_s_commands"></a>
#### 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.
<a name="_Alice_s_just_looking_commands"></a>
#### 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 <git log options>
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 <git diff options>
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.
<a name="_Alice_s_action_commands"></a>
#### 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
<a name="_what_next_"></a>
### 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*.
<a name="_note_to_the_admin_configuration_variables"></a>
### 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 ;-)

156
t/t67-hub Normal file
View file

@ -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