Review Board now plays nice with inaccessible SVN commits

If using ACLs to limit access to parts of a Subversion tree, both the New Review Request page and the commits API would break. Inaccessible commits appear in the commit log, but with no data other than a revision. No date, no message, no author, and we expected at least a date to appear.

So that’s fixed up now. Such commits are now shown in the commits list, though with minimal information. Ideally, we’d completely filter these out when querying for them, but that doesn’t seem doable. At least things aren’t totally broken now!

Read More

Djblets now has a Travis-CI

We used to have a whole, internal automated build system that tested Review Board, Djblets, Django Evolution, etc. against a variety of Python and Django versions. This was responsible for automated tests, nightly builds, website doc generation, and so on.

We’re getting this going again, but this time we’re using Travis-CI. To start off, we’re testing this with Djblets. The testing is minimal, but at least it’s there, and we’ll expand it as we go. Here it is.

Read More

Extensions can now reference static assets from Djblets/Review Board

I’ve made some fixes to the extension packaging today that allow stylesheets in an extension to reference assets (images, fonts, other stylesheets) found in Review Board or Djblets. This wasn’t working before, due to some assumptions Django makes when it comes to post-processing and packaging of static files.

Django allows you to define a list of static namespaces with a given name, and any static path starting with that name is looked up in that resource. So, djblets/images/<blah> or rb/fonts/<blah>.

Works great in templates and everywhere else, except for static file packaging. There, the assumption appears to be that any referenced resources live in the same app. The paths built are always relative to the directory or the top of the static namespace, making it impossible to do the kind of references an extension author would want.

Well, almost impossible. I pretty much beat that into submission. And here it is: https://reviews.reviewboard.org/r/7437/

Read More

Converting database evolutions to Django migrations

May have made some progress toward this today…

When you upgrade Review Board, sometimes it needs to modify your database. This will happen if we’ve added new fields, or tables, or renamed a field, or deleted one, or, you know, databasey things like that. This sort of modification is a database schema migration, and they must be done carefully. They also must support all the databases we support (MySQL, PostgreSQL, SQLite).

Historically, for us, this has been done by Django Evolution. Back before Django 1.7, there was no support for database schema migrations, but some clever people came to the rescue with Django Evolution. We’ve been using it since Review Board 1.0 alpha, and for the past several years, we’ve been maintaining it.

Here’s what it does, in a nutshell:

  • It lets us define what changes need to be made in a database-agnostic way, through “evolution files.”
  • It figures out what changes have already been applied (through a table that tracks those changes) and what changes still need to be applied.
  • It then converts those evolution files into a set of mutation operations, optimizes them, and then converts them to SQL statements suitable to the database.

Now, Django 1.7 finally has support for migrations, but of course the format is wildly different. For in-house projects, this is no big deal. You update the database one last time with Django Evolution, then use Django’s migrations from there on out. That doesn’t work with Review Board, though, since any user can go from any release to any release.

We cannot ever upgrade our Django dependency without solving this problem. Oh yeah, and Review Board extensions are affected as well.

So how do we handle this? Well, this is the game plan:

  • Write a converter to convert the evolution files to Django migration files.
  • Add a hook just before Django’s migration attempt, that imports the Django Evolution history into Django migration’s format. It would do this for any unimported apps, so we need to track those.
  • Write some compatibility shims that convert evolution commands to matching Django migration commands, and begin a deprecation phase.

Seems sorta straight-forward, right? Well, this stuff is always more complicated than it should be, so we’ll see.

I’m on step 1, and so far, this is looking like it’ll work. Expect some long posts with descriptions of how gracefully I’m bashing my head into the wall shortly.

Read More

Djblets now mostly works with Django 1.8!

Djblets is our Django utility library full of reusable components for Review Board. It has datagrids (which powers the dashboard), the API framework, the extension framework, dynamic site configuration, and lots of other utilities.

We just landed a set of changes to bring compatibility with Django 1.8! Let me tell you, going from 1.6 to 1.8 is a huge process, and retaining compatibility with both is not easy. Still, this is a big step.

That’s going into Djblets 0.9, but experimentally. We may actually lock Djblets 0.9 to Django 1.6.x, in order to prevent scenarios where a user upgrades Djblets and it accidentally pulls in the wrong version of Django. We’ll see, though

Also, this does not mean Review Board is anywhere near supporting Django 1.8. That’s a loooong ways off. Review Board 3.0 at the earliest. There’s a lot of work to do there still, and a lot of work to do in Django Evolution to convert to Django’s new migrations support.

(That part is scary.)

Read More

The road to Review Board 2.5

f you’ve been following our development for a while, we’ve been working on a big 2.5 release. This started off as a nice little feature release that was going to focus on API tokens, Webhooks, and a handful of other features, but has since evolved to include a UI refresh and preliminary mobile support.

It’s taken longer than we’d like, surely. That happens in software, and we’re still a pretty small team with very full plates. The good news is, we’re getting pretty close to release.

So here’s where we are now:

  • We’re feature-frozen, but still polishing things.
  • We’re fixing bugs here and there (though things are looking quite stable so far).
  • Getting ready to release beta 2 (soon!)
  • Followed by a RC release, and then the final 2.5!

Awesome. So, we’re getting there. Follow us on our ChangeLog, and you’ll get to watch as we get closer and closer to the final 2.5 release.

Read More

Better branch navigation with git-j

One of Git’s core strengths are its simple, light-weight branches. Spend any time working with Git and you’ll soon develop the habit of creating feature branches for any change. As your project grows, you may start to introduce release branches, hotfix branches, and long-running feature branches.

Navigating between branches becomes a common task. A simple git checkout <branchname> is all it takes. Not so bad, but if you’re frequently switching between branches, all the typing can add up.

That’s where git-j comes in.

git j is not only faster to type than git checkout, but it also offers some quick shortcuts for fast branch navigation, making it just as easy as directory navigation.

Here, I’ll show you.

Go up a branch with git j ..

Much like directory navigation, git j .. jumps to the nearest parent branch.

Let’s say you have this branch scheme:

o [topicB] [HEAD]
|
o [topicA]
|
o [master]
|

Say you want to go down a level to topicA, do some work, and then go down again to master. Using git j ..:

$ git j ..
# Do some work
$ git j ..

Now you’re on master. Check out the savings compared to git checkout:

$ git checkout topicA
# Do some work
$ git checkout master

Hey look, you’ve saved 22 keystrokes!

Jump to your previous branch with git j -

Ever find yourself switching back-and-forth between two branches? We have a handy shortcut for that.

Let’s go back to our branch scheme from before. You’re on topicB, and you need to go down a branch to topicA, do some work, and jump back to topicB.

Simple.

$ git j ..
# Do some work
$ git j -

Much nicer than the alternative:

$ git checkout topicA
# Do some work
$ git checkout topicB

That’s another 23 keystrokes saved.

Use aliases for common branches

You probably have a few branches you’re frequently on, and I bet one of them is master. Let’s say that another is release-1.0.x. Oh, let’s also throw in something like 2.0/big-refactor on top of that.

How often are you typing those branch names? Every typo any of them? I sure have.

We can shorten all those names with git j alias. Let’s give them nice, short, easy-to-remember names:

$ git j alias m=master
$ git j alias 1.0=release-1.0.x
$ git j alias rf=2.0/big-refactor`

Now instead of typing those branch names, all you have to do is pass the aliases to git j, like so:

$ git j m
$ git j 1.0
$ git j rf

Much nicer than:

$ git checkout master
$ git cehckout release-1.0.x
$ git checkout 2.0/big-refactor

Wouldn’t you say?

I use that m alias all the time, since practically all Git repositories have a master branch. Instead of setting up an alias for all of them, I can make a global alias:

$ git j alias -g m=master

Now git j m will work wherever I go!

To unset an alias, just pass an empty branch name:

$ git j alias rf=

By the way, if you ever need to check which aliases you’ve set up, just simply type git j aliases. For global aliases, git j aliases -g.

Working with branch history

git j keeps track of which branches you’ve checked out most recently, and makes it easy to jump between them.

Simply run git j history to see what your branch history looks like.

Want to quickly jump to a branch in your history? git j <number> is all you need. For instance, git j 2 will jump 2 branches back in your history.

Putting it all together

Okay, here’s a big, real-world-ish example. Our Review Board repository has master and release-2.0.x branches, and I’ve introduced a my-feature branch. In this example, I’m going to:

  1. Work on release-2.0.x.
  2. Rebase my-feature on top of it.
  3. Merge it into release-2.0.x.
  4. Merge the latest release-2.0.x changes into master.
  5. Go back to working on release-2.0.x.

First, here’s how you’d traditionally do this with Git:

# 1. Work on release-2.0.x.
$ git checkout release-2.0.x

# 2. Rebase my-feature on top of it.
$ git checkout my-feature
$ git rebase release-2.0.x

# 3. Merge it into release-2.0.x.
$ git checkout release-2.0.x
$ git merge my-feature

# 4. Merge the latest release-2.0.x changes into master.
$ git checkout master
$ git merge release-2.0.x

# 5. Go back to working on release-2.0.x.
$ git checkout release-2.0.x

Now let’s try it with git j, and with a couple of aliases (m for master, 2.0 for release-2.0.x):

# 1. Work on release-2.0.x.
$ git j 2.0

# 2. Rebase my-feature on top of it.
$ git j my-feature
$ git rebase release-2.0.x

# 3. Merge it into release-2.0.x.
$ git j ..
$ git merge my-feature

# 4. Merge the latest release-2.0.x changes into master.
$ git j m
$ git merge release-2.0.x

# 5. Go back to working on release-2.0.x.
$ git j -

How’s that for less typing? As you start to work with git-j, it’ll all start feeling more natural, just like walking a filesystem.

Get started with git-j today!

Simply clone our dev-goodies repository and stick dev-goodies/bin/git-j somewhere in your path. Or, stick all of dev-goodies/bin/ in your path to get easy access to all our scripts.

We’ll talk more next week about another extremely useful git script we provide called git-rebase-chain. Stay tuned!

Read More

An effective RBTools workflow for Git

One of the beautiful things about Git is that you have so many ways of making it work for you. This is also one of the frightening things about Git, particularly if you’re just starting out. There’s loads of documentation and blog posts covering all the ways you can use Git to manage your code or shoot yourself in the foot.

A question we’re often asked is how Git is supposed to be used with Review Board or RBCommons.

“How should I post changes,” they ask. “How should I land them?”

“Well,” we say, “that’s up to you… but here’s how we do it.”

One branch per review request

Branches in Git are pretty great. They’re light-weight, and you can really choose when and how to use them.

What we like to do is have one branch for every review request we’re still working with. Maybe they’re branching off of master, or maybe off of another change you have up for review… doesn’t matter.

Create the branch, and create as many commits on it as you want. You’re going to post these all for review under one review request. For our example, we’ll use 2 commits.

$ git checkout -b my-branch-1 master
$ vim foo.py
$ git commit -a
$ vim bar.py
$ git commit -a

Now let’s create another branch off of that, and make one commit here. This will be for your second review request.

$ git checkout -b my-branch-2
$ vim foo.py
$ git commit -a

Your tree now looks like this:

o [my-branch-2]
|
o [my-branch-1]
|
o
|
o [master] [origin/master]
|

Great, let’s post!

We’ll post that first change for review (my-branch-1). Since it’s based off of origin/master, this will be easy (since by default, that’s what’s diffed against). We just post like so:

$ git checkout my-branch-1
$ rbt post
Review request #1001 posted.

https://reviewboard.example.com/r/1001/
https://reviewboard.example.com/r/1001/diff/

Excellent. If you go to that first URL, you’ll see your summary and description filled in from your commit messages. You can edit these to your liking.

If your server has any default reviewers set up, they’ll be assigned. You might also want to fill in some bug, add some testing information. Do whatever you want to do there and publish the review request.

Now sit back and relax and… oh wait, you have a second change ready for review! Thanks to Git and RBTools, you don’t have to wait on that. Let’s post that one too.

$ rbt post my-branch-1..my-branch-2
Review request #1002 posted.

https://reviewboard.example.com/r/1002/
https://reviewboard.example.com/r/1002/diff/

What you’re doing here is posting all the commits on my-branch-2 that were made since my-branch-1. No need to push my-branch-1 first, or really worry about it in any way.

You’ll probably want to set the Depends On field to point to your other review request, as a hint to any reviewers deciding which to review first.

Oh, here’s some short-hand. If you’re already on my-branch-2, you can make use of HEAD instead of spelling out my-branch-2. In this case, this branch only has one commit, so you could also leave out my-branch1... All of these are therefore equivalent:

$ rbt post HEAD
$ rbt post my-branch-1..HEAD
$ rbt post my-branch-1..my-branch-2

This is probably familiar to you if you’re used to Git. You can use any Git SHA/tag/branch/revision range you want when calling rbt post.

Note: If you’re posting against a remote branch other than origin/master, you’ll need to either pass --tracking-branch=myremote/mybranch on any RBTools command, or set TRACKING_BRANCH = "myremote/mybranch" in .reviewboardrc. The remote must match the configured repository on Review Board.

Need to make some changes? -u to the rescue!

So someone found a flaw in your otherwise perfect code. Happens to the best of us. In both review requests, you say? Okay, we’ll let that slide for now.

Let’s update the first change. Lots of options here. You can make a new commit with the fixes, or you can amend the commit.

If it’s just a fix made in a previously un-pushed commit, we like to amend. Your choice.

$ git checkout my-branch-1
$ vim bar.py
$ git commit -a --amend
$ rbt post -u
Review request #1001 posted.

https://reviewboard.example.com/r/1001/
https://reviewboard.example.com/r/1001/diff/

Now on to the second. We’ll probably want the latest from my-branch-1 as well, so we can rebase or merge. We like to rebase when this stuff is still in flux and not yet pushed, and we like to merge when the history starts to matter (that is, when the code is in some kind of decent, landable shape).

Again, your call.

$ git checkout my-branch-2
$ git rebase my-branch-1
$ vim foo.py
$ git commit -a --amend
$ rbt post -u HEAD
Review request #1002 posted.

https://reviewboard.example.com/r/1002/
https://reviewboard.example.com/r/1002/diff/

The -u flag updates an existing review request that matches your commit message. If you’ve modified the summary or description in any way, it may prompt you for any review requests that mostly match. Just say yes or no.

Great, publish those changes. Eventually the code will be perfect.

Got your “Ship It!”? Time to land!

RBTools 0.7 and higher comes with a nifty little command, rbt land. This command takes a branch, verifies that it’s been reviewed, and lands the changes.

Let’s land both of your branches, one after the other.

$ git checkout master
$ rbt land --dest=master --push my-branch-1
$ rbt land --dest=master --push my-branch-2

This will verify that my-branch-1 is approved (at least one “Ship It!” and no open issues). It will then merge my-branch-1 into master, push it, and delete the old branch. Then it’ll verify, merge, push, and delete my-branch-2.

Each branch you land will be merged into master, with a merge commit containing the summary, description, bug numbers, and review request URL. If you want to instead squash each branch into a single commit on master, you can use --squash.

You can use --dry-run to see what will happen without actually changing your tree. Useful when you first start off.

You can also edit the commit message using --edit, or leave out --push if you don’t want to push the branch, or add --no-delete-branch if you don’t want to delete the branches. You can also set the default branch to land into. The documentation goes into all the options that are available.

Closing out landed review requests

We like to set up our review requests to auto-close when pushing commits. This is designed to work with rbt land.

When you land a change, the commit message will contain a line saying something like:

Reviewed at https://reviewboard.example.com/r/1001/

The auto-close hooks will see that and automatically close your review request, so you don’t have to.

And that’s how we do it.

There’s really a lot of options here. Some people push changes and then use the web UI to post them for review. Some people generate their own diffs and upload them. Some like to merge their own branches.

That’s all a lot of work, though. Our method give us:

  • Nice code organization, since every review request has its own dedicated branch.
  • Fast posting and updating of review requests.
  • Less mess. No extra branches sticking around, and review requests are automatically closed.
  • Confidence that every landed change has been approved. No slip-ups with pushing the wrong branch.

Give it a try!

Read More

Composing workflows using aliases in RBTools

RBTools 0.7 introduced support for aliases, a handy way to simplify common tasks and workflows when working with source code and review requests.

With aliases, you can write your own RBTools commands that expand into, well, anything. They could be a set of common options for an existing command, or they could call out to shell commands.

You can define your own aliases for your personal use, but you can also define aliases for your entire team. Since they live in .reviewboardrc, aliases can be committed to your repository for everyone to use. This is quite powerful, as it can help to easily standardize workflows for your whole team.

I’m going to show you a few ways to compose workflows using aliases.

Simplify posting code for review

Feature branches in Git are great. They help you to stay organized when you have lots of changes that depend on each other. If you’ve made heavy use of them, you’ve probably used this workflow a bit:

# Post some code...
$ rbt post HEAD

# After making some changes to code...
$ rbt post -u HEAD

# After making some changes to the commit message...
$ rbt post -g yes -u HEAD

There aren’t a lot of parameters there, but you still have to remember them and type them every time. The -u HEAD or the -g yes -u HEAD gets repetitive.

Let’s add a few nice and short aliases in ~/.reviewboardrc:

ALIASES = {
    # Post this
    'pt': 'post HEAD',

    # Post this and update
    'ptu': 'post -u HEAD',

    # Post this, update, and re-guess the description from the commit message
    'ptug': 'post -g yes -u HEAD',
}

Now the workflow becomes simply:

# Post some code...
$ rbt pt

# After making some changes to code...
$ rbt ptu

# After making some changes to the commit message...
$ rbt ptug

Much shorter, and hopefully easier to remember.

Run unit tests before posting code

If your project has a unit test suite, you’re probably supposed to run it before posting code for review. It’s easy to forget, or to just ignore it, since it’s another step in your process. We can solve both of those problems.

Say your project has a ./scripts/run-tests.sh that runs your test suite and outputs 1 for failure, 0 for success. Let’s make an alias that ensures tests pass before posting, and we’ll even pre-populate the Testing Done field with a message stating they pass. Let’s call this p for short.

ALIASES = {
    'p': '!./scripts/run-tests.sh &&'
         'rbt post --testing-done="Unit tests pass." $*',
}

Now you’ll never forget to run tests, and you’ll even have less to type.

ProTip: Define this as an alias in the .reviewboardrc in your repository, and switch your team to use that instead of rbt post.

Sanity-check patches on a review request

If you’re the gatekeeper for your project’s code (perhaps you’re an open source developer?), you need to test the patches that other people write before landing them. Thanks to rbt patch, you can easily pull down a diff from a review request and apply it, but you still need to run your tests before landing it. You also need to be careful not to disturb any changes in your own tree, or to test on the wrong branch.

To really sandbox your testing, your ideal workflow may look something like this:

$ git clone -b master . /tmp/test-project-<review request id>
$ cd /tmp/test-project-<review request id>
$ rbt patch <review request id>
$ ./scripts/runtests.sh
$ cd -
$ rm -rf /tmp/test-project-<reviw request id>

Let’s make an alias for this:

ALIASES = {
    'test-patch': '!rm -rf /tmp/test-project-$1 &&'
                  'git clone -b master . /tmp/test-project-$1 &&'
                  'cd /tmp/test-project-$1 &&'
                  'rbt patch $1 &&'
                  './scripts/runtests.sh &&'
                  'rm -rf /tmp/test-project-$1',
}

Now you have a quick and easy way to check any patch applying to the repository you’re currently in, without messing up your repository, typing a bunch of commands, or worrying about directories.

Screenshot a window and attach it in one go

If you’re doing UI work, you’re posting screenshots a lot. This means taking a screenshot, saving it somewhere, and drag-and-dropping it into a review request with a caption.

Let’s get that down to one command.

Now, different operating systems have different tools for capturing a screenshot. I’ll show an example for MacOS X and another for Linux. For Windows, you’ll need to grab a command line screenshot tool.

ALIASES = {
    # For MacOS X:
    'attach-screenshot': '!screencapture -wo /tmp/screenshot.png &&'
                         'rbt attach --caption "$2" $1 /tmp/screenshot.png &&'
                         'rm /tmp/screenshot.png',

    # For Linux:
    'attach-screenshot': '!import /tmp/screenshot.png &&'
                         'rbt attach $* tmp/screenshot.png &&'
                         'rm /tmp/screenshot.png',
}

Now uploading a screenshot is quick and easy! To upload to review request #123, just run:

$ rbt attach-screenshot 123

You can even attach a caption or custom filename, like so:

$ rbt attach-screenshot --caption="About dialog" --filename=about-dlg.png 123

Share your workflows!

We’d love to hear about any workflows you come up with. Send them along. We may even feature them in a future post or as samples in the documentation!

Read More

Auto-close review requests when pushing commits

Happy new year, everyone! Hope your holidays were fun and relaxing, with great company and wonderful memories. Mine certainly was, and now I’m back with some more tips and tricks to help you get the most out of Review Board and RBCommons.

Last time, we discussed some tips for getting the most out of your Review Board dashboard. This time, let’s talk about how to keep your dashboard clean by automatically closing review requests when pushing changes.

Introducing the post-commit hook

Post-commit hooks are a feature supported by many types of repositories and code hosting services. They allow you to execute custom code when pushing a commit, which is useful for kicking off a build, updating a website, or, in our case, closing a review request.

For self-hosted repositories, this is usually a script that you drop in a directory. This script can talk to Review Board through the RBTools API.

For repositories hosted on services like GitHub or Bitbucket  these are often set up as URLs that the service can POST to. Review Board 2.0+ have some convenient URLs just for this purpose. We’ll talk about these first.

Configuring auto-close for GitHub and Bitbucket

If you’re running Review Board 2.0.7 or higher, we’ve made it very easy to get set up. Simply log into your administration UI and click Repositories. You should see a [Hooks] link beside any GitHub or Bitbucket repositories. Click it, and you’ll get exact instructions on how to get set up.

Do this for every repository you care about. Then, whenever you’re going to push a commit, make sure it has this line in the commit message:

Reviewed at <review request url>

Where, of course, the <review request url> is the full URL to the review request page. The hook will see that line, and close the matching review request for you, complete with information on the commit ID and the branch it landed on.

The upcoming RBTools 0.7 release will make it very easy to include this automatically with a couple new commands. We’ll cover these in a new post once that release is out.

One important caveat: These services need to be able to talk to your server. That means if you’re behind a firewall, you must grant access to these services and forward a port. If you’re on RBCommons, this won’t be a problem, though. And if you’re a GitHub user, look into using GitHub Enterprise with Power Pack for Review Board  for a much more secure code hosting solution.

Configuring auto-close for custom Git repositories

Custom repositories are a bit trickier, because you need a custom script for your setup.

If you’re running Git, we have a script just for you! All you have to do is fill in some of the details in the script, rename it to post-receive, and drop it into your official Git repository’s hooks directory.

Not running Git? Unfortunately, there’s some work you’ll need to do for now. We’re working on some new scripts for Subversion and Mercurial, but if you feel up to it, you can put together your own post-commit hook, based on ours. All the communication is taken care of for you by RBTools.

Speaking of RBTools

We’re gearing up for a major RBTools release, with the goal of shipping it this week. If all goes according to plan, we’ll be back next week with an overview of the new features, and how they’ll help you get your code posted and landed faster than ever.

Read More