Skipping Travis CI builds for snapshot release commits with sbt-release

If you use sbt-release with the MAJOR.MINOR.PATCH and MAJOR.MINOR.PATCH+1-SNAPSHOT style of release versioning, this creates two commits when you run sbt release that differ only in the contents of the version.sbt file.

Unfortunately, if you're using a continuous integration system like Travis CI, those two commits both trigger full builds. There's really no point for that, since there's no difference in the code. Fortunately, Travis CI (and other systems) support marking a commit with [ci skip] to skip the build.

You can customize the commit message by changing the releaseCommitMessage setting. However, releaseCommitMessage is used for both the commitReleaseVersion and commitNextVersion actions, so some conditional logic is needed.

The default value looks like this:

releaseCommitMessage := s"Setting version to ${if (releaseUseGlobalVersion.value) (version in ThisBuild).value else version.value}"

Change releaseCommitMessage so that if the version ends with "-SNAPSHOT" then " [ci skip]" is appended to the message:

releaseCommitMessage := "Setting version to " +
  s"${if (releaseUseGlobalVersion.value) (version in ThisBuild).value else version.value}" +
  s"${if (if (releaseUseGlobalVersion.value) (version in ThisBuild) else version).value.endsWith("-SNAPSHOT")) " [ci skip]" else ""}"

Now you'll end up with release commits that look like "Setting version to 1.2.3" and snapshot commits that look like "Setting version to 1.2.4-SNAPSHOT [ci skip]".

— March 18, 2017

Acing the technical interview

No time for descriptive variables, examples, or docstrings here. In the whiteboard interview, time is of the essence. Pretend you are a Haskell programmer, as your grandmother was, before her continuation passed.

— March 17, 2017

My favorite books of 2016

Time for my annual round up of books read in the past year with a few favorites noted.

Cadillac Desert

Cadillac Desert: The American West and Its Disappearing Water, Marc Reiser

This is an eye-opening story of man's hubris in the American West. Attempting to make the desert bloom led to uncountable environmental destruction. As the climate changes and water patterns change, will we attempt to hold on to the "Cadillac desert" at huge expense, or let farmers and communities wither? The present Oroville Dam disaster would fit right in as a chapter in this book.


Sapiens: A Brief History of Humankind, Yuval Noah Harari

Breezy and fun, but with a lot to think about. This book stuck with me.

My Ántonia

My Ántonia, Willa Cather

Based on reading this back in 2007, I consider it one of my favorite novels. So much so that we named our daughter after the title character. I was worried that I wouldn't like it, but, if anything, the nostogia of the novel hit me harder now that I'm older.

From Bauhaus to Our House

From Bauhaus to Our House, Tom Wolfe

I am sure Tom Wolfe is an enormous dick in real life, but wow is his skewering of modernist architecture funny and satisfying.

San Francisco: La grille sur les collines<

San Francisco: La grille sur les collines / San Francisco: The Grid meets the Hills, Florence Lipsky

This is a fascinating and unique book about how San Francisco's street grid is adapted to the landscape. Through a combination of greed, incompetence, hubris, and Yankee ingenuity, San Francisco's city planners overlaid the standard American gridiron street pattern onto the penninsula's topography. The result is San Francisco's wildly undulating streets, which sometimes dead end spectacularly. Despite their best efforts, sometimes the grid could not be made to fit the landscape. These deformations are a major focus of the book and it features photos and illustrations of the effects in many neighborhoods across the city:

Telegraph Hill

For more pages from the book, check out this post on Map Library.

Below is the complete list of books I read in 2015:

Cadillac Desert: The American West and Its Disappearing Water, Marc Reisner

Grounded: The Case for Abolishing the United States Air Force, Robert M. Farley

Sapiens: A Brief History of Humankind, Yuval Noah Harari

A Shortage of Engineers, Robert Grossbach

The Wise Man's Fear, Patrick Rothfuss

Snowpiercer: The Escape, Jacques Lob, Jean-Marc Rochette (illustrator), and Virginie Selavy (translator)

Hyperbole and a Half: Unfortunate Situations, Flawed Coping Mechanisms, Mayhem, and Other Things That Happened, Allie Brosh

My Ántonia, Willa Cather

The Alchemist, Paolo Bacigalupi

Straight Man, Richard Russo

Decisive: How to Make Better Choices in Life and Work, Chip Heath and Dan Heath

Alice's Adventures in Wonderland Lewis Carroll

Through the Looking-Glass and What Alice Found There, Lewis Carroll

Liar's Poker: Rising Through the Wreckage on Wall Street, Michael Lewis

The Night Sessions, Ken MacLeod

How We Got to Now: Six Innovations That Made the Modern World, Steven Johnson

Terminal World, Alastair Reynolds

Success and Luck: Good Fortune and the Myth of Meritocracy, Robert H. Frank

Deadpool: The Complete Collection Volume 1, Daniel Way et al.

Minority Report, Philip K. Dick

From Bauhaus to Our House, Tom Wolfe

Wolf: The Lives of Jack London, James L. Haley

San Francisco: La grille sur les collines / San Francisco: The Grid Meets the Hills, Florence Lipsky

Pump Six and Other Stories, Paolo Bacigalupi

Bébé Day by Day: 100 Keys to French Parenting, Pamela Bruckerman

Glup: Adventures in the Alimentary Canal, Mary Roach

Wine Wars: The Curse of the Blue Nun, the Miracle of Two Buck Chuck, and the Revenge of the Terroirists, Mike Veseth

Disrupted: My Misadventure in the Start-up Bubble, Dan Lyons

The Swerve: How the World Became Modern, Stephen Greenblatt

You can also check out lists from previous years: 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, and 2015.

— March 9, 2017

A Low-Cost Solution to Traffic

In Governing magazine, William Fulton raises a consequence of compact urban areas that I had not realized fully. Even if a place is car dependent -- public transit is inadequate for its residents needs -- it can still reduce traffic if the people who live there don't have to drive as far because everything is relatively close together. Compact urban areas reduce traffic simply by being compact.

Which brings us to proximity. One of the few ways around this problem is to build more housing close to the urban cores -- or, at least, close to the dense suburban job centers. Urban planners often argue for locating more housing along high-frequency transit lines, which makes sense because many people can commute by transit.

What’s not well understood, however, is that well-located housing can cut down on the amount of driving -- and hence the need for additional road space -- even if people are still tethered to their cars. One famous study in the San Francisco Bay Area found that people living in Berkeley and Oakland drive only half as far as people in the outer suburbs -- not because they take transit more, but because the places they have to go are closer together.

— February 12, 2017

Grid corrections

Sometimes when riding gravel races (which mostly follow roads laid out on the Jeffersonian grid), I would come to a T intersection. I never really thought about why this happens, but Gerco de Ruijter has turned it into an art project:

By superimposing a rectangular grid on the earth surface, a grid built from exact square miles, the spherical deviations have to be fixed. After all, the grid has only two dimensions.

The north-south boundaries in the grid are on the lines of longitude, which converge to the north. The roads that follow these boundaries must dogleg every twenty-four miles to counter the diminishing distances: Grid Corrections.

Grid Corrections (a one minute) from Gerco de Ruijter on Vimeo.

— January 1, 2017

How to accept gifts for a Vanguard 529

We recently set up a 529 account to save for our daughter's college education. You can accept gifts from grandparents and others with a 529, but it's surprisingly difficult to find out how this works. It took me a while to figure out; hopefully writing this down will save someone out there some time.

To accept gifts for a Vanguard 529, you need to link the account to Ugift.

To do this with Vanguard, log in and click "Go to my 529 plan account area". This launches a new window for 529 account management.

Vanguard go to 529 account management

Next, click on "Ugift" in the side bar and fill out the form to generate your Ugift code.

Vanguard UGift integration

Once you do, you'll see instructions about how to share the code and can also download a PDF for relatives who prefer to contribute offline.

Once you have the code, you can provide it to benefactors to input at Ugift

UGift input code

Upon entering the code, they'll see the beneficiary's name, so they'll know they're contributing to the right kid.

UGift gift form

Hope this helps you. And Nia's code is really V6G-V7J as shown above, in case you feel like helping out.

— December 21, 2016

Fixing "Permission denied (publickey)" when connecting to a Travis CI build container

I was attempting to debug a build with Travis CI's SSH connection option (sadly, I can't find any documentation about this feature -- it's the "Debug job" button).

After the Debug job starts up, it prints:

Use the following SSH command to access the interactive debugging environment: ssh <random-string>

But when I tried this, I got:

Permission denied (publickey).

It took me a while to figure out why this was happening. What public key should a temporary SSH connection use? After talking to my co-workers, who reported no problems connecting, I remembered I had set up a separate public key for GitHub. By specifying that key with -i I was able to connect:

ssh -i ~/.ssh/id_github_rsa <random-string>

— December 13, 2016

What San Francisco Says About America

Thomas Fuller returns to the US after nearly 30 years abroad, mostly in developing countries. He is shocked by the in-your-face poverty of San Francisco.

Of course some of what I’ve encountered has been less alluring. During all my years in Asia I constantly grappled with the perniciousness of poverty. Yet somehow I was unprepared for the scale and severity of homelessness in San Francisco.

The juxtaposition of the silent whir of sleek Tesla electric vehicles, with the outbursts of the mentally ill on the sidewalks. Destitution clashing with high technology. Well-dressed tourists sharing the pavement with vaguely human forms inside cardboard boxes.

One possible reason for this is the lack of continuity in rich countries. There are fewer gaps to fill, so a person is either in the system, or completely outside it.

During a trip back to Bangkok I spoke about this paradox with Nopphan Phromsri, the secretary general of the Human Settlement Foundation, an organization that assists the homeless there.

Greater Bangkok, a sprawling metropolis with more than 10 million people, has 1,300 homeless people, a survey this year found.

San Francisco has less than one-tenth Bangkok’s population but six times as many homeless people. I’m sure you could fill a book with the reasons for this. Ms. Nopphan believes that homelessness is more intractable in rich societies. “In wealthy countries there are systems for everything,” she said. “You’re either in the system or out of the system.” There is no in-between in America. In Bangkok, by contrast, rich and poor coexist. There are vast tracts of cheap, makeshift homes and a countryside where people in the cities can return to if they lose their jobs or hit hard times.

— September 19, 2016

The American tropics

The New York Times provides a visualization of the steady Northern march of extreme heat due to global warming. By 2060, much of the country will experience 20+ days a year above 100º F.

By the end of the century, that will expand to include almost the entire country except for Northern coastal areas, the West coast and the high Rockies.

It's easy to see this as a map of where not to live. It must also be a call to action. Unfortunately, it feels like we are slipping past the point of no return. The feedback cycles are already in motion. Even with massive cuts in carbon emissions, radical geoengineering may be our only option to preserve the climate our species has prospered in for the last 50,000 years.

— August 23, 2016

Adding a command to list recently changed git branches (three ways)

I wanted to add a command to make it easy for me to see what branches I'd worked on recently. Between different projects, bugfixes, and code reviews, I end up switching branches a lot, and it can be hard to remember the names of the branches I need to polish up for submitting as a pull request and merging. It's also useful to find branches that can be deleted.

This is a git command to show all the branches sorted by date descending (branch names may be changed to protect the innocent):

git for-each-ref --sort -committerdate refs/heads/

1b46ebacca9d6a4f49698b59577e21254471f6ac commit refs/heads/look/fp-email-on-first-completion
875686cd2b9db4fe45b24a96299f71933f6599fa commit refs/heads/master
9ef1d512fcc6e05dc5b80121e1e3768c011bb167 commit refs/heads/look/document-position-metadata
ed6df9b73e2c38d74ee3419c71ee488703c8cb27 commit refs/heads/look/fix-dp-500
7b130aceaeafe31077265b6a1b7cdabd1f8329d4 commit refs/heads/look/improve-document-position-caching
fcb726b5372255a3b1c50eac1c04cf5eda4587d4 commit refs/heads/look/remove-rails-4-caching-hacks
bd1f3df97cfd3dcbe9803770fd24944bed01f236 commit refs/heads/look/remove-rails-3-code
9b6bc693e5273cf3a7ddea1062462ae333c1bb6a commit refs/heads/look/fix-selenium-rails-4
c231b29f083b14d7cdb698e8f4d2be105bc32e45 commit refs/heads/look/fix-account-router
8d16a3868f8a12961ee8dbcaa383fae7a10ebcd8 commit refs/heads/look/handle-invalid-content-hash
fe50ecee84e6017dfa444bb426c4ac7c9929fa50 commit refs/heads/look/unknown-format-rails-4
3bfe056947a351151d0e3cf18a61f30e9e03209b commit refs/heads/look/pluck
e903be6d8f2a2a170d913b5e77801600ec49023d commit refs/heads/look/match-array
bb07270a5045c737f60530ca1d3b8b17e2cdf7bb commit refs/heads/look/fix-change-column
bca2a817b32395576fe2c10be53b02022689ba75 commit refs/heads/look/rails-4-fixes
70c6e053c89e066f1eed0038faa1834ca255b4d4 commit refs/heads/look/GET_LOCK-sucks
07176fb95a802a3ca5dfcce5d3757d9831ef7d52 commit refs/heads/look/refactor-query-execution
5cb599fc57c7729ea8ed76f62ccd930b774a4d9c commit refs/heads/engine_index_refactor
(... dozens of branches omitted ...)

Adding a bit of formatting makes and piping to head makes the output easier to read:

git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15    

2016-08-04 17:59:50 -0700 4 days ago refs/heads/look/fp-email-on-first-completion
2016-08-04 17:24:34 -0700 4 days ago refs/heads/master
2016-08-04 15:02:23 -0700 4 days ago refs/heads/look/document-position-metadata
2016-08-02 13:27:42 -0700 6 days ago refs/heads/look/fix-dp-500
2016-07-28 12:24:30 -0700 11 days ago refs/heads/look/improve-document-position-caching
2016-07-19 19:55:07 -0700 3 weeks ago refs/heads/look/remove-rails-4-caching-hacks
2016-07-19 18:45:06 -0700 3 weeks ago refs/heads/look/remove-rails-3-code
2016-07-19 18:07:56 -0700 3 weeks ago refs/heads/look/fix-selenium-rails-4
2016-07-19 15:03:15 -0700 3 weeks ago refs/heads/look/fix-account-router
2016-07-18 17:36:24 -0700 3 weeks ago refs/heads/look/handle-invalid-content-hash
2016-06-30 18:49:33 -0700 6 weeks ago refs/heads/look/unknown-format-rails-4
2016-06-29 19:18:17 -0700 6 weeks ago refs/heads/look/pluck
2016-06-29 19:17:18 -0700 6 weeks ago refs/heads/look/match-array
2016-06-29 11:17:49 -0700 6 weeks ago refs/heads/look/fix-change-column
2016-06-21 14:36:50 -0700 7 weeks ago refs/heads/look/rails-4-fixes

This is a lot of typing, though! The easiest way to shorten it is to create a Bash alias:

alias grecent="git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15"

However, I wanted to make this a new subcommand, because I have trouble remembering to use Bash aliases.

The first thing I looked into was using a Bash function:

function git() {
    if [[ $@ == 'recent' ]]; then
        command git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15
        command git "$@"

This intercepts invocation of the git command. If the argument is recent, it runs my command. Otherwise, it passes the arguments to the git command (the Bash command builtin is used so it can call the real git). One thing I learned writing this is that getting the quoting right is super important.

That's not the only way to do it, though!

You can also add a git alias. Since this version doesn't take an argument, that's fairly simple:

        recent = !git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15

Because I only want to show some of the recent items, I need to invoke the alias as a shell command using ! so I can use head. You can also add arguments to git aliases, but it is a bit more complicated.

Another way is to add a new executable named git-recent to your $PATH (Antonio Santos Velasco has a good tutorial about this.). This will enable you to type git recent to invoke it. I have a ~/bin directory that is on my path, so that is a pretty easy place to stash such a command. If you want to add argument parsing (for example, to change the default number of recent items), using a stand-alone script is probably the easiest way.

Here's the full git-recent script:



git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -$ITEMS

You can invoke it like this to get the default number of recent branches:

git recent

Or specify the number of branches:

git recent 10

Now that I have an easy way of listing recently changed branches, I use it constantly. It's been super useful for me. Maybe it will be for you, too.

— August 15, 2016