﻿<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text" xml:lang="en">Semantic Release</title>
  <link type="application/atom+xml" href="https://d.moonfire.us/tags/semantic-release/atom.xml" rel="self" />
  <link type="text/html" href="https://d.moonfire.us/tags/semantic-release/" rel="alternate" />
  <updated>2026-07-22T17:35:48Z</updated>
  <id>https://d.moonfire.us/tags/semantic-release/</id>
  <author>
    <name>D. Moonfire</name>
  </author>
  <rights>Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</rights>
  <entry>
    <title>Semantic Release and Woodpecker CI</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2022/08/07/semantic-release-and-woodpecker-ci/" />
    <updated>2022-08-07T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2022/08/07/semantic-release-and-woodpecker-ci/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="semantic-release" scheme="https://d.moonfire.us/tags/" label="Semantic Release" />
    <category term="woodpecker-ci" scheme="https://d.moonfire.us/tags/" label="Woodpecker CI" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <category term="gitea" scheme="https://d.moonfire.us/tags/" label="Gitea" />
    <category term="conventional-commits" scheme="https://d.moonfire.us/tags/" label="Conventional Commits" />
    <category term="gitversion" scheme="https://d.moonfire.us/tags/" label="GitVersion" />
    <category term="lefthook" scheme="https://d.moonfire.us/tags/" label="Lefthook" />
    <category term="sourcehut" scheme="https://d.moonfire.us/tags/" label="Sourcehut" />
    <category term="fedran" scheme="https://d.moonfire.us/tags/" label="Fedran" />
    <category term="project-layout" scheme="https://d.moonfire.us/tags/" label="Project Layout" />
    <summary type="html">In my migration from GitLab to Gitea, I've started moving my CI/CD server over to Woodpecker. Here is some of the struggles I've done through in the process of getting it to work.
</summary>
    <content type="html">&lt;p&gt;With the recent drama of &lt;a href="/tags/gitlab/"&gt;GitLab&lt;/a&gt;, both with the CI/CD changes and then more recent possible threat of deleting old repositories, I continue my migration to a local &lt;a href="/tags/gitea/"&gt;Gitea&lt;/a&gt; instance, &lt;a href="https://src.mfgames.com/"&gt;https://src.mfgames.com/&lt;/a&gt; for the bulk of my code and writing.&lt;/p&gt;
&lt;p&gt;For the most part, migrating is just a matter of shuffling data. I have a &lt;em&gt;lot&lt;/em&gt; of repositories, both active and inactive, and it will take me months to move them over. Plus I haven't decided if I'm going to purge them from my GitLab account so there is a single source of truth or just mirror back to them.&lt;/p&gt;
&lt;p&gt;Currently, the most difficult task was figuring out how to handle the build processing. I've mentioned previously that I use &lt;a href="/tags/conventional-commits/"&gt;Conventional Commits&lt;/a&gt; and &lt;a href="/tags/semantic-release/"&gt;Semantic Release&lt;/a&gt; fairly heavily. I've branched out a little from there using &lt;a href="/tags/lefthook/"&gt;Lefthook&lt;/a&gt; and my &lt;a href="/garden/project-layout/"&gt;project layout&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Currently, the CI does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build the project&lt;/li&gt;
&lt;li&gt;Test various conditions including valid commit messages&lt;/li&gt;
&lt;li&gt;If the commits indicate a new build:
&lt;ol&gt;
&lt;li&gt;Tag it&lt;/li&gt;
&lt;li&gt;Build the release version&lt;/li&gt;
&lt;li&gt;Create a release on Gitea&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This changes over time, but it is the basic pattern.&lt;/p&gt;
&lt;h1&gt;Tags and Git Depth&lt;/h1&gt;
&lt;p&gt;Woodpecker does not automatically download the needed tags for &lt;code&gt;semantic-release&lt;/code&gt; (and &lt;a href="/tags/gitversion/"&gt;GitVersion&lt;/a&gt;). This means that the &lt;code&gt;.woodpecker.yml&lt;/code&gt; file needs to include tags.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;clone:
    git:
        image: woodpeckerci/plugin-git
        settings:
            tags: true
pipeline:
    # The pipeline elements
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unike GitLab, which only limits to the last ten commits, it appears that Woodpecker &lt;a href="https://woodpecker-ci.org/plugins/plugin-git"&gt;downloads the full repository&lt;/a&gt; by default which is also needed by GitVersion because it calculates every version. Not entirely sure about &lt;code&gt;semantic-release&lt;/code&gt; logging indicates it doesn't need the full repository, just enough back to find a version.&lt;/p&gt;
&lt;h1&gt;Building and Testing&lt;/h1&gt;
&lt;p&gt;To support task branches, I have a basic build and test code that runs on pushes and pull requests. This lets me identify bugs earlier and catch typos with my commits.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;build:
    image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
    commands:
        - nix develop --command scripts/build.sh
    when:
        # We need both &amp;quot;tag&amp;quot; for the next section.
        event: [push, pull_request, tag]
        tag: v*

test:
    image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
    commands:
        - nix develop --command scripts/test.sh
    when:
        event: [push, pull_request]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the build tasks, you can see that I'm using my current project layout which uses scripts in the &lt;code&gt;scripts/&lt;/code&gt; folder instead of &lt;code&gt;npm run&lt;/code&gt; or &lt;code&gt;dotnet run&lt;/code&gt;. This is to make it easier to work with polyglot plus works around the issue that I need to use &lt;code&gt;nix develop&lt;/code&gt; to get into my reproducible environment since the Docker image doesn't automatically do that. This is because both Gitlab and Woodpecker use the image which bypasses initialization files and I couldn't have it run &lt;code&gt;direnv allow&lt;/code&gt; automatically to set up environment variables.&lt;/p&gt;
&lt;p&gt;One thing that is missing is that Woodpecker doesn't have a clean mechanism for temporary build artifacts. I can't upload the build files and then download them so I can see the final results. Instead, I have to script it out or use a S3 plugin.&lt;/p&gt;
&lt;h1&gt;Building on Versions&lt;/h1&gt;
&lt;p&gt;With most cases, I build the release version of the project when the conventional commits indicate that there is a new version (&lt;code&gt;feat&lt;/code&gt; and &lt;code&gt;fix&lt;/code&gt;). This is an additional pipeline that comes after the &lt;code&gt;test:&lt;/code&gt; line.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;release-main:
    image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
    commands:
        - export DRONE=&amp;quot;true&amp;quot; # Required to convince `env-ci`
        # semantic-release needs this locally
        - git branch $DRONE_BRANCH origin/$DRONE_BRANCH
        - nix develop --command scripts/release.sh
    secrets:
        - gitea_token
        - git_credentials
    when:
        event: push
        branch: main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a number of things in this block that took me a while. The first is the &lt;code&gt;event&lt;/code&gt; and &lt;code&gt;branch&lt;/code&gt;. We only do releases on the &lt;code&gt;main&lt;/code&gt; (I'm still moving away from &lt;code&gt;master&lt;/code&gt; as racist language).&lt;/p&gt;
&lt;p&gt;The second is the &lt;code&gt;export DRONE&lt;/code&gt; line. At the time I set this up, &lt;a href="https://www.npmjs.com/package/env-ci"&gt;env-ci&lt;/a&gt; wasn't aware of Woodpecker, but it was &lt;a href="https://github.com/woodpecker-ci/woodpecker/pull/1035"&gt;recently added&lt;/a&gt; thanks to 6543 on the Woodpecker Matrix channel, &lt;code&gt;#woodpecker-ci:matrix.org&lt;/code&gt;. I don't know when the latest &lt;code&gt;semantic-release&lt;/code&gt; will have it, but it shouldn't be needed soon, if not already.&lt;/p&gt;
&lt;p&gt;The third is the &lt;code&gt;git branch&lt;/code&gt; line in the above script. Woodpecker creates a detached head, as does Gitlab. But when it doesn't do is also create a local branch for the one being created. This causes a problem because the release process appears to &amp;ldquo;jump&amp;rdquo; to the branch to figure out the changes between the detached head (the commit being built) and the actual branch.&lt;/p&gt;
&lt;p&gt;Finally, we have the secrets. &lt;code&gt;semantic-release&lt;/code&gt; automatically picks up $GITEA_TOKEN for the release process but also needs $GIT_CREDENTIALS to verify Git access.&lt;/p&gt;
&lt;p&gt;The token is easy, that is what given by Gitea for the user.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md"&gt;GIT_CREDENTIALS&lt;/a&gt; is slightly harder, it is a colon-separate tuple of the user name and the Gitea access token. From observations, the Gitea is basically just a bunch of URL-safe characters, so the URL-escaping isn't needed in my case (you need to URL-escape the left and right of the colon but not the colon itself).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ export GITEA_TOKEN=9fc6d72c72e4b149f07491a0b2d3ec9215d57caf
$ export GIT_CREDENTIALS=&amp;quot;dmoonfire:$GITEA_TOKEN&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These need to be set on a per-project basis since Woodpecker, unlike GitLab and &lt;a href="/tags/sourcehut/"&gt;sourcehut&lt;/a&gt;, there doesn't appear to be a good way of having a shared set of secrets for projects (GitLab has organization/group level secrets, sourcehut has the secret storage). This means I have to set the same GITEA_TOKEN and GIT_CREDENTIALS for all 80+ of my &lt;a href="/tags/fedran/"&gt;Fedran&lt;/a&gt; repositories†.&lt;/p&gt;
&lt;p&gt;† Woodpecker has a CLI, &lt;code&gt;woodpecker-cli&lt;/code&gt; which will let me automate that. I will use that.&lt;/p&gt;
&lt;h1&gt;Create Release on Tag&lt;/h1&gt;
&lt;p&gt;One thing I'm moving toward is creating a release entry on the forge. Since this happens after the build process and Woodpecker uses a different Docker image, I need it to be a post-release event so I hang it off the tagging process instead of the push to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;6543 came to my rescue again with this one, so that is why there are those two &amp;ldquo;tag&amp;rdquo; elements in the script above. I also have a new stanza for the release process:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;release-gitea:
    image: plugins/gitea-release
    settings:
        base_url: https://src.mfgames.com
        files:
            - &amp;quot;*.pdf&amp;quot;
            - &amp;quot;*.epub&amp;quot;
        api_key:
            from_secret: gitea_token
    when:
        event: tag
        tag: v*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I didn't have the &lt;code&gt;event:&lt;/code&gt; and &lt;code&gt;tag:&lt;/code&gt; in the &lt;code&gt;build:&lt;/code&gt; stanza, it wasn't working for the tags. This caused me some difficulties because I usually treat hashes as being unordered, but Woodpecker uses file order for processing pipelines. So, I needed to have the &lt;code&gt;build:&lt;/code&gt; target build the file (with the correct version because it was tagged) and then &lt;code&gt;release-gitea:&lt;/code&gt; to use that output for the release process. The &lt;code&gt;test:&lt;/code&gt; and &lt;code&gt;release-main:&lt;/code&gt; are skipped because they don't have those events listed.&lt;/p&gt;
&lt;p&gt;In addition, secrets are handled differently when done as a parameter for a plugin. That is why I have the &lt;code&gt;from_secret:&lt;/code&gt; element in the above script. This inconsistency threw me for a few days.&lt;/p&gt;
&lt;h1&gt;Putting it Together&lt;/h1&gt;
&lt;p&gt;If you want to see the final version, check out &lt;a href="https://src.mfgames.com/dmoonfire-garden/project-layout/src/branch/main/.woodpecker.yml"&gt;this example&lt;/a&gt; which has my current version as a single file.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I'm happy to move over to Woodpecker (you know, except for the cost of hosting) both because of the control and the challenge. I also don't have a need for speed, so if it takes a while to get through the queue, I'm okay.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Integrating Semantic Versioning into MfGames Writing</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2018/08/27/mfgames-writing-releases/" />
    <updated>2018-08-27T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2018/08/27/mfgames-writing-releases/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="writing" scheme="https://d.moonfire.us/categories/" label="Writing" />
    <category term="markdown" scheme="https://d.moonfire.us/tags/" label="Markdown" />
    <category term="mfgames-writing" scheme="https://d.moonfire.us/tags/" label="MfGames Writing" />
    <category term="semantic-release" scheme="https://d.moonfire.us/tags/" label="Semantic Release" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">How to release a novel or story using MfGames Writing.
</summary>
    <content type="html">&lt;p&gt;The final component of this &lt;a href="/tags/mfgames-writing/"&gt;MfGames Writing&lt;/a&gt; series is how to integrate &lt;a href="/blog/2018/08/13/publishing-processes/"&gt;semantic releases&lt;/a&gt; into the publication process.&lt;/p&gt;
&lt;p&gt;If you want to use &lt;a href="http://sentimentalversioning.org/"&gt;sentimental versioning&lt;/a&gt;, 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.&lt;/p&gt;
&lt;h1&gt;Series&lt;/h1&gt;
&lt;p&gt;I appear to be writing a short series of post about the tools I use for publication and writing.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/13/publishing-processes/"&gt;Semantic Versions and Releases&lt;/a&gt;: Why semantic versioning helps with the writing process.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/21/mfgames-writing-reasons/"&gt;Evolution of MfGames Writing&lt;/a&gt;: A brief history and reasoning behind the tools.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/22/mfgames-writing-init/"&gt;First Steps Using MfGames Writing&lt;/a&gt;: Starting a new project with MfGames Writing.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/23/mfgames-writing-content/"&gt;Adding Content to MfGames Writing&lt;/a&gt;: Adding front and back matter to novels.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/24/mfgames-writing-docker-and-ci/"&gt;Working with MfGames Writing, CI, and Docker&lt;/a&gt;: Adding automatic building with commits.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/25/mfgames-writing-formats/"&gt;Additional Formats for MfGames Writing&lt;/a&gt;: How to create PDF, MOBI, DOCX, and HTML versions.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/26/mfgames-writing-themes/"&gt;Theming for MfGames Writing&lt;/a&gt;: A light introduction on how to customize the output.&lt;/li&gt;
&lt;li&gt;Integrating Semantic Versioning into MfGames Writing: Tying semantic releases into the process.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;NPM Packages&lt;/h1&gt;
&lt;p&gt;Like everything else, we pull in a number of packages from NPM to handle the release process.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ npm install
npm install \
  @commitlint/cli \
  @commitlint/config-conventional \
  @semantic-release/changelog \
  @semantic-release/git \
  commitizen \
  cz-conventional-changelog \
  husky \
  semantic-release
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;@commitlint&lt;/code&gt; is to make sure we have a consistent commit messages (the &lt;code&gt;feat:&lt;/code&gt; and &lt;code&gt;fix:&lt;/code&gt; stuff). This makes sure everything else works smoothly.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;@semantic-release&lt;/code&gt; packages are to do the release process.&lt;/p&gt;
&lt;p&gt;The two packages, &lt;code&gt;commitizen&lt;/code&gt; and &lt;code&gt;cz-conventional-changelog&lt;/code&gt;, are used to help guide you through creating the commits if you are unfamiliar with it. When these are installed, you can use &lt;code&gt;git cz&lt;/code&gt; instead of &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, &lt;code&gt;husky&lt;/code&gt; is used to make sure you follow the commits correctly because it will reject the commit if you don't follow conventions.&lt;/p&gt;
&lt;h1&gt;Configuration&lt;/h1&gt;
&lt;p&gt;The bulk of the configuration happens inside &lt;code&gt;package.json&lt;/code&gt;. This file can get pretty big, so I'm only going to list the differences.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
    &amp;quot;scripts&amp;quot;: {
        &amp;quot;commitmsg&amp;quot;: &amp;quot;commitlint -E GIT_PARAMS&amp;quot;
    },
    &amp;quot;release&amp;quot;: {
        &amp;quot;branch&amp;quot;: &amp;quot;master&amp;quot;,
        &amp;quot;message&amp;quot;: &amp;quot;chore(release): v${nextRelease.version}\n\n${nextRelease.notes}&amp;quot;,
        &amp;quot;verifyConditions&amp;quot;: [
            &amp;quot;@semantic-release/changelog&amp;quot;,
            &amp;quot;@semantic-release/git&amp;quot;
        ],
        &amp;quot;analyzeCommits&amp;quot;: [&amp;quot;@semantic-release/commit-analyzer&amp;quot;],
        &amp;quot;prepare&amp;quot;: [
            &amp;quot;@semantic-release/changelog&amp;quot;,
            &amp;quot;@semantic-release/npm&amp;quot;,
            &amp;quot;@semantic-release/git&amp;quot;
        ],
        &amp;quot;publish&amp;quot;: [],
        &amp;quot;success&amp;quot;: [],
        &amp;quot;fail&amp;quot;: []
    },
    &amp;quot;commitlint&amp;quot;: {
        &amp;quot;extends&amp;quot;: [&amp;quot;@commitlint/config-conventional&amp;quot;]
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Updating .gitlab-ci.yml&lt;/h1&gt;
&lt;p&gt;To actually use this, we have to modify the GitLab setup slightly.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;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:
            - &amp;quot;*.pdf&amp;quot;
            - &amp;quot;*.epub&amp;quot;
            - &amp;quot;*.mobi&amp;quot;
            - &amp;quot;*.docx&amp;quot;
            - &amp;quot;*.html&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two new lines are what does the release process.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;- npx commitlint --from=master to=CI_BUILD_REF_NAME
- npx semantic-release
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;What Does This Give You&lt;/h1&gt;
&lt;p&gt;So, given the amount of setup, what does this give you? Every time you push up a &lt;code&gt;feat:&lt;/code&gt; or &lt;code&gt;fix:&lt;/code&gt;, it will do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bump the version to the next appropriate one (1.0.0 to 1.1.0 for example).&lt;/li&gt;
&lt;li&gt;Generate the EPUB, MOBI, etc file.&lt;/li&gt;
&lt;li&gt;Create or update the &lt;code&gt;CHANGELOG.md&lt;/code&gt; file with the summary of your changes.&lt;/li&gt;
&lt;li&gt;Tag the version in Git with &lt;code&gt;v1.1.0&lt;/code&gt; (for example).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;This isn't for everyone but I have found it very helpful when working with others.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Semantic Versions and Releases for Publishing</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2018/08/13/publishing-processes/" />
    <updated>2018-08-13T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2018/08/13/publishing-processes/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="writing" scheme="https://d.moonfire.us/categories/" label="Writing" />
    <category term="flight-of-the-scions" scheme="https://d.moonfire.us/tags/" label="Flight of the Scions" />
    <category term="mfgames-writing" scheme="https://d.moonfire.us/tags/" label="MfGames Writing" />
    <category term="semantic-release" scheme="https://d.moonfire.us/tags/" label="Semantic Release" />
    <category term="semantic-version" scheme="https://d.moonfire.us/tags/" label="Semantic Version" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">Over the last few weeks, I've been tweaking my publishing process to automate more of the release and generation process.
</summary>
    <content type="html">&lt;p&gt;Over the last few weeks, I've been tweaking my publishing process. I think I have something pretty stable and started using it for my &lt;a href="/tags/flight-of-the-scions/"&gt;next novel&lt;/a&gt;. After talking about it on social networks, a number of people suggested I write up what I've learned.&lt;/p&gt;
&lt;h1&gt;Series&lt;/h1&gt;
&lt;p&gt;I appear to be writing a short series of post about the tools I use for publication and writing.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Semantic Versions and Releases: Why semantic versioning helps with the writing process.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/21/mfgames-writing-reasons/"&gt;Evolution of MfGames Writing&lt;/a&gt;: A brief history and reasoning behind the tools.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/22/mfgames-writing-init/"&gt;First Steps Using MfGames Writing&lt;/a&gt;: Starting a new project with MfGames Writing.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/23/mfgames-writing-content/"&gt;Adding Content to MfGames Writing&lt;/a&gt;: Adding front and back matter to novels.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/24/mfgames-writing-docker-and-ci/"&gt;Working with MfGames Writing, CI, and Docker&lt;/a&gt;: Adding automatic building with commits.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/25/mfgames-writing-formats/"&gt;Additional Formats for MfGames Writing&lt;/a&gt;: How to create PDF, MOBI, DOCX, and HTML versions.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/26/mfgames-writing-themes/"&gt;Theming for MfGames Writing&lt;/a&gt;: A light introduction on how to customize the output.&lt;/li&gt;
&lt;li&gt;&lt;a href="/blog/2018/08/27/mfgames-writing-releases/"&gt;Integrating Semantic Versioning into MfGames Writing&lt;/a&gt;: Tying semantic releases into the process.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Software Processes&lt;/h1&gt;
&lt;p&gt;Much of how I manage writing projects is to treat them like software. It works well for framing what I have done, need to get done, and what the end goal is. Because of this, I use various features of &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt; pretty heavily: issue tracking for arcs, issues for the publication process, and even more to remind me to order books; milestones to keep me encouraged; continuous integration (CI) to simplify the production of EPUB, MOBI, and PDF versions of the file.&lt;/p&gt;
&lt;p&gt;I've also written a number of framework tools such as &lt;a href="https://gitlab.com/mfgames-writing/"&gt;MfGames Writing&lt;/a&gt; to work with CI services for the publication or help me manage stuff (&lt;code&gt;markdowny&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Recently, I got into a discussion about treating novels as software. Some of the things I do are&amp;hellip; strict and not everyone will care for them, but I like to think I'm making my reader's lives easier by the little details that go into my processes.&lt;/p&gt;
&lt;h1&gt;Semantic Versioning&lt;/h1&gt;
&lt;p&gt;Somewhere in 2014 or so, I fell in love with &lt;a href="https://semver.org/"&gt;semantic versioning&lt;/a&gt;. Semantic versioning is a movement to create a common understanding (a grammar) of version numbers that can be understood by anyone to understand the significance of any given release.&lt;/p&gt;
&lt;p&gt;A semantic version comes in three parts: major.minor.patch.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a major number increases, it means there was a &amp;ldquo;breaking change&amp;rdquo;. In writing terms, it would be rewriting sections, changing motivations, removing scenes, and generally changing the meaning of the novel. I would say adding a new epilogue would be reasonably called a major change because it changes the meaning and plot of the novel.&lt;/li&gt;
&lt;li&gt;A minor version is adding features or improvements. As I see it, a minor version is one that I would be adding details to clarify a scene, make it more obvious or more understandable. Maybe adding a paragraph or so would be a minor change.&lt;/li&gt;
&lt;li&gt;Finally, there is a patch. This is fixing typos, character names, or the missing quotes. Sadly, I seem to have a lot of patches as I write, because I only notice those annoying little things days or weeks later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I put the version on the legal page so it is present but not obvious unless one is looking for it. There are a number of reasons I do this. The biggest is &lt;em&gt;The Deeds of Paksenarrion&lt;/em&gt; by Elizabeth Moon. I have two copies of this omnibus book, mainly because I love it so much. They are two different printings. One of them had a few typos in it that they corrected with a later printing. Having an indicator that there were changes (in this case, a &amp;ldquo;patch&amp;rdquo;) would tell me there is something different about these two books.&lt;/p&gt;
&lt;p&gt;Lucas, with his reworking of the first three &lt;em&gt;Star Wars&lt;/em&gt; movies, would have either new features (the new crowd scenes at the end of &lt;em&gt;The Return of the Jedi&lt;/em&gt;) or breaking changes (Greedo shooting first). An example of a patch is redoing the unintended transparency of the X-Wing dash during the fight scenes or reworking the undercarriage of the hover car in the desert (Vaseline verses CGI).&lt;/p&gt;
&lt;p&gt;I want to know those changes so when I look at a copy and notice that only the last number changed, it just means there were some typo fixes. If the first, then I start to ask questions, why?&lt;/p&gt;
&lt;p&gt;This is also important because some authors will rewrite their books after publication. I also use it when sending books out to alpha and beta readers. Since I get the responses in a semi-random order, it is easier to know that I'm getting feedback from version 0.4.0 instead of 0.5.0. With Git, I can create a branch, manually handle the edits, and then pull them back into the master branch which will then help me consolidate changes between two versions.&lt;/p&gt;
&lt;p&gt;Figuring out what goes where (major, minor, or patch) can be a rough.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Sand and Blood&lt;/em&gt;, I'm on version 3.1.0. I switched to version 2.0.0 when I made the book &lt;a href="https://creativecommons.org/"&gt;Creative Commons&lt;/a&gt;. A license change (from &amp;ldquo;All Rights Reserved&amp;rdquo;) felt like a breaking change. I bumped to 3.0.0 when I realized there was a major plot hole about how the clans dealt with the dead (they don't talk about it), so I &lt;em&gt;removed&lt;/em&gt; some conversations because I had a better understanding of the world after &lt;em&gt;Sand and Ash&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;Changes&lt;/h1&gt;
&lt;p&gt;There is an important part about version numbers: why. Knowing that someone bought version 1.1.2 of a book and now I'm on 3.1.0 would beg the question: what major changes have happened.&lt;/p&gt;
&lt;p&gt;That is where the &lt;a href="https://fedran.com/sand-and-blood/changelog/"&gt;change log&lt;/a&gt; comes in. I'm still working on the format, but I try to document every version of the book, from major to minor to patch. That way, someone can look at the versions and decide for themselves if they want a copy (or to ask for a replacement, which I've done also).&lt;/p&gt;
&lt;h1&gt;Semantic Releases&lt;/h1&gt;
&lt;p&gt;Of course, the problem with change logs is that they require some effort to maintain. Over the last year, I stumbled on the concept of a &lt;a href="https://semantic-release.gitbook.io/semantic-release/"&gt;semantic-release&lt;/a&gt;. A semantic release is an extension of the version but it automates much of the processes that are involved with figuring out what type of number has to be bumped in the version and creating the appropriate log entries.&lt;/p&gt;
&lt;p&gt;One of the goals is to be &lt;a href="http://sentimentalversioning.org/"&gt;unromantic&lt;/a&gt; about version numbers. I'll admit, I've been romantic about the versions up to this point, but there is something about the systems approach to versions that takes the human factor out and reduces the amount of work.&lt;/p&gt;
&lt;p&gt;Basically, &lt;a href="https://github.com/semantic-release/semantic-release"&gt;semantic-release&lt;/a&gt; is a workflow for NPM packages (and novels in my case) that automates the calculations of verison numbers and also updates the change. It has plugins for publishing that I could use to update my website with the latest versions whenever I make a minor change.&lt;/p&gt;
&lt;p&gt;It also means that the versions are much smaller. Instead of having 5-10 items in a release, there is probably just one change between versions.&lt;/p&gt;
&lt;h1&gt;Commit Conventions&lt;/h1&gt;
&lt;p&gt;Since I work with Git, there is one component that needs to be done to make semantic-release: conventions. In specific, I use &lt;a href="https://conventionalcommits.org/"&gt;conventional commits&lt;/a&gt; which is a standards to identify if something is a minor (a &amp;ldquo;feature&amp;rdquo;) or a patch (&amp;ldquo;fix&amp;rdquo;). These are done by a &lt;em&gt;convention&lt;/em&gt; of the commit messages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;feat: integrated edits from Marta B&lt;/li&gt;
&lt;li&gt;fix: fixed a typo with Rutejimo's missing accent&lt;/li&gt;
&lt;li&gt;ci: trying to get it to build on GitLab&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The semantic-release package parses the commit messages (in specific, the &lt;a href="https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines"&gt;Angular&lt;/a&gt; conventions) and figures out if it should be releases (any &amp;ldquo;BREAKING CHANGES&amp;rdquo;, &amp;quot;feat:&amp;quot;, or &amp;ldquo;fix:&amp;rdquo; that it sees). Other commits don't bump up the version but still give me the ability to make changes.&lt;/p&gt;
&lt;p&gt;I like the structure of using conventional commits and having it automatically feed into new version numbers and creating the change log. Later, it can be used to automate my &lt;a href="https://fedran.com/"&gt;website&lt;/a&gt; and maybe even publish books on various vendors.&lt;/p&gt;
&lt;p&gt;This automation is also important for authors published by the various &lt;a href="https://typewriter.press/"&gt;Typewriter Press&lt;/a&gt; imprints. All of them have access to their source files in GitLab. They can make changes without me approving of them. If they follow the same conventions, then it will bump up to the versions for &lt;em&gt;their&lt;/em&gt; corrections without me tracking them or asking what changed. In that way, it allows non-technical writers to also participate in this process; all without getting overwhelmed by the technical details while still not requiring them to keep track of changes.&lt;/p&gt;
&lt;h1&gt;Tracking&lt;/h1&gt;
&lt;p&gt;Since the version number is pulled into the legal page, it also means that I can easily manage alpha and beta readers, different rounds of editors, and even coordinate changes after giving out multiple copies at the same time (my alpha and beta readers are concurrent).&lt;/p&gt;
&lt;h1&gt;Software&lt;/h1&gt;
&lt;p&gt;Much of these concepts also apply to my tools, so I also switched all of MfGames Writing tools to use semantic-release and automate the deployment. Like writing, it lets me focus on what I want to do (write) and automate the tedious stuff (release management).&lt;/p&gt;
</content>
  </entry>
</feed>
