First, some basic concepts about the Leanpub API. See the documentation for the full details, I’m only mentioning clear some things you need to know to understand the rest of this post.
Book slug: Each Leanpub book is identified by a slug, which is basically an unique author-chosen identifier for the book. The book slug is included in the book’s Leanpub URL. For example, the URL for Learning Hammerspoon is https://leanpub.com/learning-hammerspoon, therefore its slug is learning-hammerspoon. The slug can be changed by the author as part of the book configuration, and is used in all the API calls to identify the book for which an operation should be performed.
The tools I describe below assume by default that your book’s git repository name is the same as its Leanpub slug. You can specify it if this is not the case by providing some additional configuration parameters.
API key: Every Leanpub author gets an API key, which is a randomly-generated string of characters which is used as an authentication token. The API key needs to be provided on most Leanpub API calls (some query operations are allowed without a key).
Build types: The Leanpub API allows you to trigger several types of build operations on a book:
Preview builds all the formats supported by Leanpub (PDF, ePub, Mobi), using the whole book as defined in the Book.txt file.
Subset preview builds only the PDF version of a book, from a subset of files defined in the Subset.txt file in your repository.
File preview builds only a segment of text you need to provide as part of the API call. I do not use this operation in my workflows.
Publish builds and publishes a new version of the book. Publishing means that it becomes the version available for purchase. Optionally, when publishing a new release you can send out an email with release notes to people who have already purchased the book (in any case, the new version of the book also becomes available for them to download).
Book writing mode refers to the source from which Leanpub gets the text for your book. I use “Git and Github”, but these techniques should work equally well with BitBucket or any other platforms that can trigger a webhook when your text is updated.
The beginning: triggering and watching builds by hand
As an initial step, I wrote some shell scripts to trigger and watch the progress of Leanpub builds by hand. I use the Elvish shell, and my scripts are published as the leanpub Elvish module. These allow you to trigger book builds (only preview and subset builds, no publishing) by hand, and also to watch the progress of any operation. If you use Elvish, you can install the module like this:
Then, whenever you commit changes to your text, you can trigger a build and watch its progress like this:
leanpub:preview # or leanpub:subset
You can combine build-and-watch in a single command:
Note that you also need to specify your Leanpub API key, which you can get and manage in the Author / Your API Key in Leanpub:
Reload your Hammerspoon configuration. Now when you trigger a preview or publish (for example, using the scripts above), you will after a few seconds start seeing the corresponding notifications.
Triggering builds with a static webhook
The most basic way of automatically triggering builds is by using a webhook to trigger the Leanpub API directly. This is described in your book’s “Getting Started” page, which you can access at https://leanpub.com/YOUR_BOOK/getting_started (replacing YOUR_BOOK with your book’s slug). This works well, but the downside is that the webhook is “hardcoded” so you can only trigger a fixed type of build per webhook (e.g. subset or regular preview). This means that if you want to trigger a different type of build, you need to keep multiple webhooks defined, and activate the one you want by hand:
Triggering builds via CircleCI
Looking for ways to further automate the preview and publish workflow of my books, I came across CircleCI, a popular CI/CD platform which is easy to use and allows creation of libraries called “orbs” to encapsulate more complex behaviors. I wrote an orb called zzamboni/leanpub for automating interactions with the Leanpub API. With it, you can set up a build/preview/publish workflow which you can trigger directly from git.
Here’s my preferred workflow (you can build others as well using the leanpub orb, see below for ideas):
A subset preview is triggered for every commit to the book’s repository. I keep Subset.txt with the same content as Book.txt, so a subset preview gives me a PDF-only build of my whole book (you could also modify Subset.txt before each commit depending on the part of the book you want to preview, but this is outside the scope of this article). This allows me to have a continuous PDF preview of any changes I make to my book.
A regular preview is triggered for commits that are tagged with a tag starting with preview. This builds the book in all the formats supported by Leanpub (PDF, epub, mobi). This allows me to check the output in all formats when I’m doing finishing touches before publishing a new version of the book, or when I make major changes.
A silent publish is triggered for commits tagged with a tag starting with silent-publish. This builds and publishes the book, but without sending out release notes. I use this for “minor” updates to the published book which I don’t think need to be widely announced (e.g. fixing typos and formatting, etc.)
Finally, a publish is triggered for commits tagged with a tag starting with publish. This builds and publishes the book, but also sends out release notes to its readers. The release notes are taken from the description of the tag (if it is an annotated tag) or from the commit message of the tagged commit (if it’s a regular tag).
To implement this workflow, all you have to do is add a file .circleci/config.yml to your repository, containing the following:
version:2.1orbs:leanpub:email@example.com# This tag-based book building workflow dispatches to the correct job# depending on taggingworkflows:version:2build-book:jobs:- leanpub/subset-preview:filters:tags:ignore:- /^preview.*/- /^publish.*/- /^silent-publish.*/- leanpub/full-preview:filters:tags:only:/^preview.*/branches:ignore:/.*/- leanpub/auto-publish:name:leanpub/silent-publishauto-release-notes:falsefilters:tags:only:/^silent-publish.*/branches:ignore:/.*/- leanpub/auto-publish:auto-release-notes:truefilters:tags:only:/^publish.*/branches:ignore:/.*/
Once you have committed this file, you can enable CircleCI on it as follows:
If you have defined static webhooks in your repository as described before, make sure to disable them.
In the “Add projects” screen, choose your repository and click “Set Up Project”. Since you have already added the config.yml file, you can skip that part and click on “Start building”.
The first build will fail because you have not provided your Leanpub API key yet:
To fix this, you need to define an environment variable called LEANPUB_API_KEY within your CircleCI project. Click on the project name, and then on the settings button at the top-left of the screen. Once there, select the “Environment Variables” section and enter the environment variable:
Now you can go to the “Workflows” screen and click on “Rerun” for your book’s workflow (alternatively, make a new commit on your git repository). Assuming you have the Leanpub Spoon installed as described before, you should see the notifications for your book’s build within a few seconds.
Using the techniques described above has made my book building and publishing much easier. I have been using them for a few weeks, and the latest release of Learning Hammerspoon was published using this workflow already. I hope you find it useful as well! Please let me know in the comments if you have any questions or feedback.