Escape shell words before showing them to the user

If anybody ever has something nefarious like a space in the path to
their TWIGGRC file or their Gem install path, this commit ensures that
we don't end up displaying a command for them to run that won't actually
work if they paste it in the shell.

For example, if TWIGGRC is `/foo/bar baz/twiggrc`, we would here print
`/foo/bar\ baz/twiggrc` in our permissions checking code, which can
safely be copied and pasted into the shell.

Change-Id: I3dfc25a75df92b25deff982635445916132a2153
Reviewed-on: https://gerrit.causes.com/25292
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Don't choke on "empty" commits

I'd tested this code previously on all of our repos as far back as 300
days ago; testing 1,000 days backs led me to hit things like commit
c31bbd58adbb9b8173d in causomatic.git, which is one of several commits
without any message at all (evidently these were produced with `git
commit --allow-empty`, which was probably an abuse of the option).

I'm going to loop back after this and add some specs to prove that we
can handle this kind of edge case, but for now I am going to blaze ahead
dealing with some other edges that the 1,000 day test has turned up.

Change-Id: Id135aa23d2308ac45f786c44600028645147ceaa
Reviewed-on: https://gerrit.causes.com/25293
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Don't die on seeing commits with invalid timezones

rails.git has some commits like 4cf94979c9f4d6683c with invalid
timezones on the committer and author lines; eg.

  committer Vijay Dev <vijaydev.cse@gmail.com> 1312735823 +051800

This is supposed to be a 4-digit number preceded by + or -, but in this
case is a 6-digit number, and a non-sensical one at that.

As we effectively ignore the timezone info anyway (we're initializing
the date based on the number of seconds elapsed since the UNIX epoch,
which is always expressed in GMT/UTC), this commit adjusts the commit
parser to not choke on the invalid timezone.

Change-Id: I1556b21d2956cdaf63905cdc81ebed109a7dcac6
Reviewed-on: https://gerrit.causes.com/25294
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Handle commits with invalid author info

We were barfing on bad commits like commit 4e873ffcdab0c445 in
rails.git, which has an author line looking like:

  author  <JRadosz@gmail.com> 1302595195 -0700

ie. no author name, just an empty string.

This commit teaches Twigg to grab both the name and the email, so that
we can fallback to the email if the name is not present. With this
change, we can parse the last 1,000 days of rails.git history without
barfing; I'll follow up with an even longer scale test after this.

Change-Id: Ibf0f1eb68dfa679c0b10164942f59001d111c4ca
Reviewed-on: https://gerrit.causes.com/25295
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Add some specs for Twigg::Repo edge cases, handling one new case

This commit adds some specs for Twigg::Repo, specifically targeting some
edge cases that we have observed with repos in the wild.

Additionally, as I decided to test a commits produced with the
combination of `--allow-empty` and `--allow-empty-message`, I discovered
an unhandled edge case, which this commit fixes.

Change-Id: Iced5d8ea2a35582953547467eba7d57938d50978
Reviewed-on: https://gerrit.causes.com/25296
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Add specs for Twigg::Repo#initialize

Change-Id: I65549a12fcadb19fbbb84ccb10bceef6bba83f32
Reviewed-on: https://gerrit.causes.com/25297
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Fix a tiny style violation in Twigg::CommitSet

Change-Id: I4cc2450fa9d8e0c9f462baf22254bcc1ea7dbc59
Reviewed-on: https://gerrit.causes.com/25298
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Add per-author aggregate stats in `stats` verbose mode

This method is long and ugly. I'll look at cleaning it up as I enhance
the handling of width calculations (ie. to make them dynamic, rather
than assuming a maximum width).

Will need to make the same change for the web app if we want to keep it
at parity with the CLI version.

Change-Id: I84ff3414651115e57e70a341ede12cdd886f4483
Reviewed-on: https://gerrit.causes.com/25299
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Teach web app to link back to GitHub for individual commits

Whenever `github.organization` is set, construct links to GitHub commits
for each commit shown in the web UI.

I added a `commit` accessor to the `Twigg::Commit` class rather than
accessing the instance variable directly for parity with the other
accessors in that class, and also for the nice touch of showing the full
commit SHA-1 in the web UI on mouseover (as a `title` attribute).

Change-Id: I6accede3deb0a7afbd45430b53a48b71b8cd7468
Reviewed-on: https://gerrit.causes.com/25300
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Teach web app to link back to GitHub for project names

In order to facilitate this, I added a `#link` method to `Twigg::Repo`,
that behaves like its counterpart on `Twigg::Commit` does (ie. if
`github.organization` is set, it returns a link; otherwise it returns
`nil`).

Likewise, I adapted to `#count_by_repo` to use real `Twigg::Repo`
objects as keys, so that I could call the `#link` method as needed to
construct the URL.

Change-Id: I622caf5dd4929ac70922a1510aafcb1a8c353931
Reviewed-on: https://gerrit.causes.com/25301
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
DRY up breakdown logic by extracting a method into Util module

We had similar logic for displaying a breakdown defined in both the
`App` and `Command::Stats` classes. Make it a little more general (ie.
capable of generating both HTML and plain-text) and extract it into the
`Util` module where it can be used by both.

Change-Id: Ifc8fa1850b87e8cf9f780ff1955051abf243492e
Reviewed-on: https://gerrit.causes.com/25302
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Remove unnecessary `surround` logic from commit_stats template

The square brackets here were really just aping the command-line
version; they aren't really needed in the GUI, where they just add
clutter.

Change-Id: I6f1fe6adb0706b96238c857c2bc132ab225e1eb6
Reviewed-on: https://gerrit.causes.com/25303
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>
Simplify use of Util in Stats class

Rather than defining a forwarding method for convenience (for
`#number_with_delimiter`), and then calling a class method (for
`.breakdown`), just include the `Util` module directly.

To prevent method leakage and reduce API surface area, mark the methods
as `private` and drop the now-superfluous `extend` call.

Change-Id: I090c06426ba673a78adec0dfb058a32277167756
Reviewed-on: https://gerrit.causes.com/25304
Reviewed-by: Greg Hurrell <greg@causes.com>
Tested-by: Greg Hurrell <greg@causes.com>