•••

Update: With Jekyll & GitHub Pages’ ability to serve extensionless permalinks, I’ve updated the article to show you how to use your own domain of top of the (ever reliable) gopkg.in - turning example.com/repo.v1 into the canonical import URL, but with gopkg.in serving the latest tag for you.

Here’s a short tutorial on how to combine GitHub Pages and gopkg.in to both version and serve your Go libraries and projects from a vanity import. Think yourdomain.com/pkgname.v1 instead of gopkg directly, or github.com/you/yourproject . This allows you to vendor your libraries without having to create multiple repositories, and therefore multiple sets of documentation, issues, and distinct/confusing import URLs.

Importantly, it works today, is maintainable, and is compatible with those vendoring your library downstream.

Note: the go-imports tag will be able to specify a branch/revision when issue 10913 is resolved, but users on older versions of Go won’t be able to pull your package down.

Domain Setup

I’ll assume you have your own domain and know enough to point a CNAME or A record for your domain to a host or IP. If not, GitHub’s documentation on this is pretty good, so reach for that if you get stuck.

Once you’ve set up the CNAME file for your GitHub Pages branch—usually gh-pages or the master branch if you have a user.github.io repository—you can get started with the rest.

Creating the Import URL

Assuming a new or existing Jekyll installation, create a new layout under _layouts in the root of your Jekyll project:

$ vim _layouts/imports.html

Put the following template into the layout you’ve just created:

<!DOCTYPE html> <html xmlns= "http://www.w3.org/1999/xhtml" xml:lang= "en" lang= "en-us" > <head> <meta http-equiv= "content-type" content= "text/html; charset=utf-8" > <!-- Go Imports --> <meta name= "go-import" content= "{{ page.go-import }}" > <meta name= "go-source" content= "{{ page.go-source }}" > <meta http-equiv= "refresh" content= "0; {{ page.redirect }}" > </head> <body> </body> </html>

We’ve also added a ‘go-source’ <meta> tag so that GoDoc knows where to fetch our API documentation from, and a re-direct so that anyone hitting that page in the browser is re-directed to GoDoc. You could alternatively have this re-direct to the domain itself, the GitHub repo or no-where at all.

We’ll also need to configure our Jekyll installation to use extensionless permalinks in _config.yml :

vim _config.yml # Site settings title: 'your project' tagline: 'Useful X for solving Y' baseurl: "/" permalink: "/:title"

Once you’ve done this, create a pkgname.vN.html file at (e.g.) root of your Jekyll project: e.g. pkgname.v1.html . Future versions

# GitHub Pages + Jekyll 3.x can serve this as example.com/pkgame.v1 without the extension. $ vim pkgname.v1.html

Now you can configure the template—this is the one you’ll re-use for future versions or other packages you create.

--- layout: imports go-import: "example.com/pkgname.v1 git https://gopkg.in/someuser/pkgname.v1" go-source: > example.com/pkgname.v1 _ https://github.com/someuser/pkgname/tree/v1{/dir} https://github.com/someuser/pkgname/blob/v1{/dir}/{file}#L{line} redirect: "https://godoc.org/example.com/pkgname.v1" ---

Commit that and push it to your GitHub Pages repository, and users can now import your package via go get -u example.com/pkgname.v1 (and eventually, a v2!).

Canonical Import Paths

Go 1.4 also introduced canonical import paths, which ensure that the package is imported using the canonical path (read: our new custom domain) instead of the underlying repository, which can cause headaches later due to duplicate imports and/or a lack of updates (if you change the underlying repo). Thankfully, this is easy enough to fix—add the canonical path alongside your package declarations:

package mypkg // import example.com/pkgname.v1

Users can’t ‘accidentally’ import github.com/you/mypkg now (it won’t compile).

Notes

As a final note, doing all of this is much easier with a new project or library. You can move an existing repository over to a custom domain, but existing users on the old import path may run into issues. Make sure to document it well!