Integrating Semantic Versioning into MfGames Writing

The final component of this MfGames Writing series is how to integrate semantic releases into the publication process.

If you want to use sentimental versioning, then you can probably skip this. I like having automatic versioning because it helps me identify the version that beta readers or an editor has when I go to integrate the changes.

Series

I appear to be writing a short series of post about the tools I use for publication and writing.

  1. Semantic Versions and Releases: Why semantic versioning helps with the writing process.
  2. Evolution of MfGames Writing: A brief history and reasoning behind the tools.
  3. First Steps Using MfGames Writing: Starting a new project with MfGames Writing.
  4. Adding Content to MfGames Writing: Adding front and back matter to novels.
  5. Working with MfGames Writing, CI, and Docker: Adding automatic building with commits.
  6. Additional Formats for MfGames Writing: How to create PDF, MOBI, DOCX, and HTML versions.
  7. Theming for MfGames Writing: A light introduction on how to customize the output.
  8. Integrating Semantic Versioning into MfGames Writing: Tying semantic releases into the process.

NPM Packages

Like everything else, we pull in a number of packages from NPM to handle the release process.

$ npm install
npm install \
  @commitlint/cli \
  @commitlint/config-conventional \
  @semantic-release/changelog \
  @semantic-release/git \
  commitizen \
  cz-conventional-changelog \
  husky \
  semantic-release

This is a pretty big and scary list, but there isn't a lot of clean ways to do this. I'll give a brief summary of them.

The @commitlint is to make sure we have a consistent commit messages (the feat: and fix: stuff). This makes sure everything else works smoothly.

The @semantic-release packages are to do the release process.

The two packages, commitizen and cz-conventional-changelog, are used to help guide you through creating the commits if you are unfamiliar with it. When these are installed, you can use git cz instead of git commit.

Finally, husky is used to make sure you follow the commits correctly because it will reject the commit if you don't follow conventions.

Configuration

The bulk of the configuration happens inside package.json. This file can get pretty big, so I'm only going to list the differences.

{
    "scripts": {
        "commitmsg": "commitlint -E GIT_PARAMS"
    },
    "release": {
        "branch": "master",
        "message": "chore(release): v${nextRelease.version}\n\n${nextRelease.notes}",
        "verifyConditions": [
            "@semantic-release/changelog",
            "@semantic-release/git"
        ],
        "analyzeCommits": ["@semantic-release/commit-analyzer"],
        "prepare": [
            "@semantic-release/changelog",
            "@semantic-release/npm",
            "@semantic-release/git"
        ],
        "publish": [],
        "success": [],
        "fail": []
    },
    "commitlint": {
        "extends": ["@commitlint/config-conventional"]
    }
}

Updating .gitlab-ci.yml

To actually use this, we have to modify the GitLab setup slightly.

image: dmoonfire/mfgames-writing-js:1.1.1

stages:
    - publish

publish:
    stage: publish
    tags:
        - docker
    script:
        - npm ci
        - npx commitlint --from=master to=CI_BUILD_REF_NAME
        - npx semantic-release
        - npm run build

    artifacts:
        expire_in: 1 week
        paths:
            - "*.pdf"
            - "*.epub"
            - "*.mobi"
            - "*.docx"
            - "*.html"

The two new lines are what does the release process.

- npx commitlint --from=master to=CI_BUILD_REF_NAME
- npx semantic-release

What Does This Give You

So, given the amount of setup, what does this give you? Every time you push up a feat: or fix:, it will do the following:

  • Bump the version to the next appropriate one (1.0.0 to 1.1.0 for example).
  • Generate the EPUB, MOBI, etc file.
  • Create or update the CHANGELOG.md file with the summary of your changes.
  • Tag the version in Git with v1.1.0 (for example).

That means, every change you do will have a distinct version. With everything else tied together, you could put it in a header and use that to figure out where to make the changes (my writing group gives me 4-12 sets of corrections, frequently overlapping).

This isn't for everyone but I have found it very helpful when working with others.

Metadata

Categories:

Tags: