views:

118

answers:

6

I'm moving my continuous testing to a dedicated server (autotest slows down my local laptop too much). What I'd like is for my testing server (which happens to be running CruiseControl.rb) to be continuously getting my latest (committed) changes via Git -- ideally, without any changes to my own workflow. I am the only developer working on this project.

Prior to getting the testing server, I had:

  • My laptop as my main development system
  • Multiple branches in my local repository.
  • A local working copy, pointing to one of the branches. I switch between branches frequently (usually for new features).
  • A GitHub account, to which I frequently push local branches to mirrored remote branches. (This is mostly for use an offsite backup; I'm not sharing any code for my current project). I try to push to GitHub at least at the end of every workday, though I occasionally forget.

I'd like to keep all of that intact. On top of that, I now have:

  • The test server
  • ...running CruiseControl.rb
  • A clone of my laptop repository on my test server. (Currently it's not cloning GitHub)
  • A local working copy on the test server, from which CC is building/testing.
  • This working copy points to one particular Git branch (of course)

I've been trying to have my test server automatically get whatever branch I'm working on on my laptop working copy and build from that. (That would mimic autotest's continuous testing without eating up system resources).

Things I've tried without success:

  • git checkout origin/HEAD: this gets the files fine but breaks CruiseControl because it doesn't like the "branchless" working copy.
  • git checkout --track -b a_branch origin/a_branch: this works fine for getting files, and CC likes it, but it sticks the testing server to a particular branch. When switching branches on the laptop I'll effectively stop testing my current work.
  • git checkout --track -b my_testing_branch origin/HEAD: this also gets buildable files, but it suffers from the same problem as the command above. Creating a branch from origin/HEAD only gets the HEAD for the "default" branch, so it's also sticky.

Is there any way I can get a good remote continuous testing system (with or without git branches) that doesn't involve major changes to my workflow?

A: 

I've considered skipping past git and going to a shared folder/NFS/rsync solution, but that has one major problem: it's not triggered by / limited to commits, so I'll end up getting false-positive broken builds while I'm in the middle of typing something.

Craig Walker
+1  A: 

You could have a dedicated testing branch on which you merge your current branch work.
You can force replacing the content of that branch with the commit of the current working branch (see git merge -s ours, what about “their” question).

Then on the CI server, you initialize it with:

 $ git fetch laptopRepo
 $ git checkout -b testingBranch laptopRepo/testingBranch

It implies one first step on the laptop side to publish some current work to test.

VonC
Not bad; it unfortunately requires an additional regular step to merge my current work into the testing branch, but so far it's the front runner. Thanks
Craig Walker
+1  A: 

This isn't the greatest solution but it's something...

The test server can run git remote show origin to see which branch is currently active on your laptop. E.g.,

$ git remote show origin
* remote origin
  Fetch URL: blade:/var/scratch/code
  Push  URL: blade:/var/scratch/code
  HEAD branch: foo
  Remote branches:
    foo tracked
    bar tracked
    qux tracked

So, the origin repository is currently on the foo branch.

I haven't seen a low level command that will give you that directly so you may have to parse it out from this (perhaps someone will have a better way). Example,

$ b=$(git remote show origin | grep "HEAD branch" | awk -F: '{print $2}')
$ echo $b
foo

Now, since origin/foo will act similar to origin/HEAD (no local branch) and your CruiseControl doesn't like that you should probably just create a local branch on the testing machine and simply hard-reset it to the latest location:

$ b=$(git remote show origin | grep "HEAD branch" | awk -F: '{print $2}')
$ git reset --hard origin/$b

Note, this is slightly fragile since HEAD me not always be what you think it is. For example, during a rebase HEAD will be moving backward and forward. If your testing server checks HEAD on your laptop during a rebase it could get some invalid or undesired location.

Pat Notz
I happened to be doing a lot of rebasing this weekend, so that is an issue. :-\
Craig Walker
+3  A: 

Another option is to write a hook that notifies the test server of new code to pull. In particular, a post-commit hook is probably a better route. Then, every time you commit you can inform the test server of what to pull and from which branch.

Pat Notz
In order for the test server to pull the latest code for testing, you have to have pushed it somewhere the server can grab it from, and I don't believe there's a post-push hook in git, and I also think that hook would run on the machine that performed the push (e.g. your laptop, not the server with the repository).
Teflon Ted
Originally, I was going totally sans-push, and having the server pull from my laptop. Pat's suggestion with a post-commit hook could work if it fires off a message to the server (ex: an ssh remote command) that causes the server to start its pull. However, I'm leaning back towards the push route currently.
Craig Walker
As a matter of fact, there's is a "post-push" hook in the form of the --receive-pack parameter to git-push
Craig Walker
+1  A: 

I've think got a pretty good solution by inverting the relationship between the two systems. Instead of having the test server pull from the laptop's repository, I could have the laptop push changes out to the server to be tested.

First I add a remote on the laptop's repo:

git remote add testing <url of testing server>

Then, whenever I have code for testing, I do a push:

git push -f testing HEAD:master

This will work from whatever branch I'm currently on. The -f ensures that I'll blow away whatever is already in that branch; I won't have to worry about any ancestry.

This won't actually put the latest code in a working copy, but CruiseControl's polling can solve that. I could also have a server-side hook that updates a working copy and runs the test suite (I wouldn't even need CC at that point).

I'll probably want to add a combined commit+push command to a script or alias; that will give me my one-command commit & test. If for some reason I want to do a commit without a test push (or vice versa), then I have those options too.

Craig Walker
That's the kind of thing you could do within your `post-commit` hook. You just need to be careful to not overwrite code that's being actively built or tested.
Pat Notz
+1  A: 

Host on GitHub and use their post-recieve hooks. That's how services like Devver and RunCodeRun do it.

Teflon Ted