﻿<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text" xml:lang="en">Gitlab</title>
  <link type="application/atom+xml" href="https://d.moonfire.us/tags/gitlab/atom.xml" rel="self" />
  <link type="text/html" href="https://d.moonfire.us/tags/gitlab/" rel="alternate" />
  <updated>2026-06-05T17:38:36Z</updated>
  <id>https://d.moonfire.us/tags/gitlab/</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>semantic-release-nuget v1.1.0</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2021/09/04/semantic-release-nuget/" />
    <updated>2021-09-04T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2021/09/04/semantic-release-nuget/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="semantic-release" scheme="https://d.moonfire.us/tags/" label="semantic-release" />
    <category term="semantic-release-dotnet" scheme="https://d.moonfire.us/tags/" label="semantic-release-dotnet" />
    <category term="semantic-release-nuget" scheme="https://d.moonfire.us/tags/" label="semantic-release-nuget" />
    <category term="mfgames-locking" scheme="https://d.moonfire.us/tags/" label="MfGames.Locking" />
    <category term="nuget" scheme="https://d.moonfire.us/tags/" label="NuGet" />
    <category term="single-responsibility-principle" scheme="https://d.moonfire.us/tags/" label="Single Responsibility Principle" />
    <category term="myget" scheme="https://d.moonfire.us/tags/" label="MyGet" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">To pair with last's week utility, I finished up the first version of semantic-release-nuget and used it.
</summary>
    <content type="html">&lt;p&gt;Last week, I wrote &lt;a href="/blog/2021/08/29/semantic-release-dotnet/"&gt;semantic-release-dotnet&lt;/a&gt; which was a &lt;a href="https://semantic-release.gitbook.io/semantic-release/"&gt;semantic-release&lt;/a&gt; plugin to automatically set the version to the appropriate one before building.&lt;/p&gt;
&lt;p&gt;One of the key parts missing from the normal .NET development cycle was also publishing the packages. I decided to break that into a separate plugin because I have a number of places where I don't want to publish but I do want something versioned (internal projects and customized deployments). So, in the essence of the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;Single Responsibility Principle&lt;/a&gt;, I created a second utility which does one thing: build and publish NuGet packages.&lt;/p&gt;
&lt;p&gt;Introducing &lt;a href="https://www.npmjs.com/package/semantic-release-nuget"&gt;semantic-release-nuget&lt;/a&gt;. It doesn't have a lot of configurations, but the documentation covers all of them. Basically, it does one thing.&lt;/p&gt;
&lt;p&gt;I mostly tested with &lt;a href="/tags/mfgames-locking/"&gt;MfGames.Locking&lt;/a&gt;, my CIL library for some thread-locking patterns, because I'm the process of carving out &lt;a href="/tags/gallium/"&gt;Gallium&lt;/a&gt; and &lt;a href="/tags/nitride/"&gt;Nitride&lt;/a&gt; into their own packages. I'm just not sure where to put them, so they are probably going in my &lt;a href="https://gitlab.com/mfgames-cil/"&gt;Gitlab&lt;/a&gt; organization until I find a &amp;ldquo;better&amp;rdquo; organization/home.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>generator-mfgames-writing v0.3.2</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2021/07/31/generator-mfgames-writing/" />
    <updated>2021-07-31T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2021/07/31/generator-mfgames-writing/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="asdf" scheme="https://d.moonfire.us/tags/" label="asdf" />
    <category term="generator-mfgames-writing" scheme="https://d.moonfire.us/tags/" label="generator-mfgames-writing" />
    <category term="commitlint-gitlab-ci" scheme="https://d.moonfire.us/tags/" label="commitlint-gitlab-ci" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <category term="semantic-release" scheme="https://d.moonfire.us/tags/" label="semantic-release" />
    <category term="conventional-commits" scheme="https://d.moonfire.us/tags/" label="Conventional Commits" />
    <category term="commitlint" scheme="https://d.moonfire.us/tags/" label="commitlint" />
    <category term="husky" scheme="https://d.moonfire.us/tags/" label="Husky" />
    <category term="fast-trip" scheme="https://d.moonfire.us/tags/" label="Fast Trip" />
    <summary type="html">Today, I finished putting the final touches on additional features for `generator-mfgames-writing`, my scaffolding generator for Yeoman that lets me set up writing projects quickly.
</summary>
    <content type="html">&lt;p&gt;Related to process of writing from &lt;a href="/blog/2021/07/27/commitlint-gitlab-ci/"&gt;a few days ago&lt;/a&gt;, I've been working on another tool that I find myself using fairly often: &lt;a href="https://yeoman.io/"&gt;Yeoman&lt;/a&gt;. This is a scaffolding tool, which basically means it asks a few questions and then sets up a project. In my case, it does a lot of the drudge work of creating a writing project and getting it ready for &lt;a href="https://gitlab.com/"&gt;Gitlab's CI&lt;/a&gt; which I also use heavily (and why I wrote &lt;code&gt;commitlint-gitlab-ci&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Like many of the writing tools, this is based on Javascript (but not Typescript this time).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ sudo npm install -g yo generator-mfgames-writing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing it does is ask a number of questions about the project. I'll use &lt;a href="https://fedran.com/nor-curse-be-found/"&gt;Nor Curse Be Found&lt;/a&gt;, my Beauty and the Beast sequel, as an example.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ mkdir nor-curse-be-found
$ cd nor-curse-be-found
$ yo mfgames-writing
? The title for your novel or story: (Nor Curse Be Found)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of my writing projects have a unique &amp;ldquo;slug&amp;rdquo; to describe them. This is used for the website's URL, such as &lt;a href="https://fedran.com/nor-curse-be-found"&gt;https://fedran.com/nor-curse-be-found&lt;/a&gt;, and also the name of the output (&lt;code&gt;dmoonfire-nor-curse-be-found-0.0.1.epub&lt;/code&gt;). I use a library to pull out the current directory's name and try to make a reasonable title out of it. I can change the title to something more accurate, maybe with apostrophes or possessives, but generally I keep the slug pretty even. In this case, the parenthetical item is the suggested output, so I can just hit return.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? The title for your novel or story: Nor Curse Be Found
? The slug based on the title: (nor-curse-be-found)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just in case the directory doesn't match the directory, I use a library to take that given title and create a slug out of it. One of the biggest things, my &lt;a href="http://www.sectorgeneral.com/shortstories/fasttrip.html"&gt;Fast Trip&lt;/a&gt; rule, is that I don't want to tell someone how to work. That is why I called this semi-opinionated in that there are a lot of options but the default is how &lt;em&gt;I&lt;/em&gt; work.&lt;/p&gt;
&lt;p&gt;There is also a question about bylines, but then we start to get into the technical bits.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? The title for your novel or story: Nor Curse Be Found
? The slug based on the title: nor-curse-be-found
? Author's name or byline: D. Moonfire
? Do you want to create the Git repository? (Y/n)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This came from some years ago, but I do one story per repository, more so if I think the story has a possibility of being a bigger piece (which many of mine are), I want to track the versions independently, or I might be sending to an editor or submitting it somewhere (not likely these days, I self-censor a lot there). Since this is so common, I put it in as part of the questions.&lt;/p&gt;
&lt;p&gt;I have a slowly evolving set of practices when it comes to writing processes. One of the first ones is setting up a Git repository. This always starts with configuring &lt;a href="https://typicode.github.io/husky/#/"&gt;husky&lt;/a&gt;, &lt;a href="https://www.conventionalcommits.org/en/"&gt;semantic-release&lt;/a&gt;, &lt;a href="https://www.conventionalcommits.org/en/"&gt;conventional-commits&lt;/a&gt;, and &lt;a href="https://commitlint.js.org/#/"&gt;commitlint&lt;/a&gt;. (I'm working on updating my &lt;a href="https://www.npmjs.com/package/generator-mfgames-writing"&gt;Yeoman generator&lt;/a&gt; to make this a lot easier, but that will be later this week.)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Do you want to create the Git repository? Yes
? Any command to run after `git init`? set-moonfire-git-user
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also write for a number of different projects (and bylines) which means I don't always use the same Gitlab login or even email. To faciliate this, I do &lt;em&gt;not&lt;/em&gt; have a global &lt;code&gt;user.name&lt;/code&gt; and &lt;code&gt;user.email&lt;/code&gt; set up in Git so it blows up if I try to make a commit without setting a local one. Since that is tedious, I write a bunch of scripts that set the user information and SSH keys (&lt;code&gt;set-moonfire-git-user&lt;/code&gt; for writing, &lt;code&gt;set-mfgames-git-user&lt;/code&gt; for programming for example) and I want to call them before I do that first commit. If I just hit return to have a blank, then nothing extra will happen.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Any command to run after `git init`? set-moonfire-git-user
? Do you want to create the initial commit? Yes
? Do you want to create the initial Git tag? Yes
? What version do you want to start? 0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the initial commit is a messy one and a philosophical difference between me and the Semantic Release folks. They have &lt;a href="https://github.com/semantic-release/semantic-release/blob/caribou/docs/support/FAQ.md#can-i-set-the-initial-release-version-of-my-package-to-001"&gt;their reasons&lt;/a&gt; to hard-code the value to &amp;ldquo;1.0.0&amp;rdquo; but I'm specifically start this process &lt;em&gt;before&lt;/em&gt; a release, so I feel it should be &amp;ldquo;0.0.1&amp;rdquo; because I want that tracking as soon as possible.&lt;/p&gt;
&lt;p&gt;Since I don't have the ability to set it via a configuration file, I get around it by creating the initial commit and then allowing it to be tagged so it can be pushed up and get the starting version I want.&lt;/p&gt;
&lt;p&gt;This is also because I tag versions I give to editors, beta readers, and even my writing group (when I went to it). The tagged version also shows up on the various Fedran pages and mainly it shows progression as I write.&lt;/p&gt;
&lt;p&gt;So, &lt;em&gt;Fast Trip&lt;/em&gt; so I jump through a few hoops. It should also be clear why I needed that command to run after &lt;code&gt;git init&lt;/code&gt; to set my user, otherwise this part would blow up with a &amp;ldquo;user not set&amp;rdquo; message.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? What version do you want to start? 0.0.1
? Which package manager do you use? (Use arrow keys)
❯ NPM
  Yarn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Moving away from Git and into the build process, the first question is package management. I have a love/hate relationships with &lt;code&gt;npm&lt;/code&gt;. The command works great, but I've been struggling with it (more on than off lately) so I've been using &lt;a href="https://yarnpkg.com/"&gt;yarn&lt;/a&gt; fairly heavily in the last year or so. But, with Yeoman I can give both so the user can use up or down keys to select and hit return to choose. Once they do, the menu goes away and is replaced with the choice.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Which package manager do you use? Yarn
? Do you want to use semantic releases? Yes
? Do you want to use conventional commits? Yes
? Do you want to use Husky? Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next three are to set up the common functionality I use with releases. They set up &lt;a href="https://semantic-release.gitbook.io/semantic-release/"&gt;semantic-release&lt;/a&gt;, &lt;a href="https://www.conventionalcommits.org/en/"&gt;conventional commits&lt;/a&gt;, &lt;a href="https://commitlint.js.org/#/"&gt;commitlint&lt;/a&gt;, and &lt;a href="https://typicode.github.io/husky/#/"&gt;Husky&lt;/a&gt; which I use to make sure all the commit messages are clean. These four program have been a stable in most of my development lately, for coding and writing, for Typescript and even C#.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Do you want to use Husky? Yes
? Do you want to use CI/CD? Yes
? Do you use Gitlab for your CI/CD? Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can't say enough for Gitlab's CI. Whenever I push up code to the server, it runs the entire publication process. Assuming it works, it then produces a zip archive with EPUB, MOBI, PDF, and other formats without me doing anything else. Every single time. With sematic releases and the rest, each one has a unique version so I don't have &amp;ldquo;final&amp;rdquo;, &amp;ldquo;final-2&amp;rdquo;, &amp;ldquo;final-2a&amp;rdquo;, etc. Just a clean version number that shows up everywhere, starting at 0.0.1.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Do you use Gitlab for your CI/CD? Yes
? Do you use asdf? No
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is another tool I use, &lt;a href="https://github.com/asdf-vm/asdf"&gt;asdf&lt;/a&gt;. This was also something that pretty much started last year, but one of the goals of &lt;a href="https://gitlab.com/mfgames-writing/mfgames-writing-js/"&gt;mfgames-writing&lt;/a&gt; was to be able to produce consistent output of novels even years later. Well, what I didn't realize is how much the Node ecosystem would change and Node 15 doesn't exactly run Node 8 packages very well due to deprecations and changing libraries.&lt;/p&gt;
&lt;p&gt;This is where &lt;code&gt;asdf&lt;/code&gt; comes in. It puts a small file (&lt;code&gt;.tool-versions&lt;/code&gt;) which says which version of Node, Yarn, C#, Python, whatever and will automatically change to those versions when I &lt;code&gt;cd&lt;/code&gt; into the directory. It basically rolls in all the functionality of &lt;code&gt;nvm&lt;/code&gt;, &lt;code&gt;virtualenv&lt;/code&gt;, and a bunch of other localized version libraries into one. Since I write and work across many languages, having one tool to manage that is easier for me. So, saying &amp;ldquo;yes&amp;rdquo; to the question copies that &lt;code&gt;.tool-versions&lt;/code&gt; into the resulting directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Do you use asdf? Yes
? Which formats do you want to use? (Press &amp;lt;space&amp;gt; to select, &amp;lt;a&amp;gt; to toggle all, &amp;lt;i&amp;gt; to invert selection)
❯◉ PDF
 ◉ EPUB
 ◯ DOCX
 ◯ HTML
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this next question, we are out of the build section and into the formats. Basically, this just queries which types of files will be written out. The directions are pretty clear, but basically this will determine which of the format libraries are included.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? Which formats do you want to use? PDF, EPUB, DOCX, HTML
? The name of the theme package to use: (@mfgames-writing/clean-theme)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I only have three themes right now, two are &amp;ldquo;generic&amp;rdquo; and one I prefer just for Fedran stories (but obviously don't prevent anyone from using it). Later, I hope to have more themes, but basically the choices are &lt;code&gt;@mfgames-writing/clean-theme&lt;/code&gt; and &lt;code&gt;@mfgames-writing/greekil-theme&lt;/code&gt; (a Gentium-based theme).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? The name of the theme package to use: @mfgames-writing/clean-theme
Creating initial Git repository
Initialized empty Git repository in fedran/nor-curse-be-found/.git/
Running custom Git command


I'm all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself.


   create package.json
    force ../../../.yo-rc-global.json
    force .yo-rc.json
   create release.config.js
   create commitlint.config.js
   create .husky/commit-msg
   create .gitlab-ci.yml
   create .tool-versions
   create publication.yaml
   create yarn.lock
   create README.md
   create .gitignore
   create chapters/chapter-01.md

Changes to package.json were detected.

Running yarn install for you to install the required dependencies.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, it just producing a wall of tell as it creates all the files, hooks up everything, and basically gets my entire project ready, including a sample first chapter, a really basic &lt;code&gt;README.md&lt;/code&gt;, and a Git repository ready to push.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ ls -a
.                     .git            node_modules       README.md
..                    .gitignore      package.json       release.config.js
chapters              .gitlab-ci.yml  package-lock.json  .yo-rc.json
commitlint.config.js  .husky          publication.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right off the bat, I can build the files and see the output.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ yarn build:pdf
... lots of output
$ ls *.pdf
nor-curse-be-found-0.0.1.pdf
$ yarn build
... huge amounts of output
$ ls nor-curse-be-found*
nor-curse-be-found-0.0.1.docx  nor-curse-be-found-0.0.1.epub
nor-curse-be-found-0.0.1.html  nor-curse-be-found-0.0.1.pdf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm also ready to push up to Gitlab.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ git remote add origin git@gitlab.com:fedran/nor-curse-be-found.git
$ git push --tags
$ git push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopping over to Gitlab, I can see it building immediately.&lt;/p&gt;
&lt;p&gt;&lt;img src="./initial-push.png" height="256" style="margin-top:1em;" alt="Initial CI Run" /&gt;&lt;/p&gt;
&lt;p&gt;As soon as it is done, it uploads the output as an artifact.&lt;/p&gt;
&lt;p&gt;&lt;img src="./gitlab-log.png" height="256" style="margin-top:1em;" alt="End of Log" /&gt;&lt;/p&gt;
&lt;p&gt;I can then click on the browse (or download) button on the right.&lt;/p&gt;
&lt;p&gt;&lt;img src="./gitlab-download.png" height="256" style="margin-top:1em;" alt="Browse and Download Buttons" /&gt;&lt;/p&gt;
&lt;p&gt;Browsing lets me see a list of all the outputs that I've added.&lt;/p&gt;
&lt;p&gt;&lt;img src="./gitlab-browse.png" height="256" style="margin-top:1em;" alt="Browse Artifacts" /&gt;&lt;/p&gt;
&lt;p&gt;And I can even click on the PDF to preview it.&lt;/p&gt;
&lt;p&gt;&lt;img src="./gitlab-pdf.png" height="256" style="margin-top:1em;" alt="View PDF" /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>commitlint-gitlab-ci v0.0.4</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2021/07/27/commitlint-gitlab-ci/" />
    <updated>2021-07-27T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2021/07/27/commitlint-gitlab-ci/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="commitlint-gitlab-ci" scheme="https://d.moonfire.us/tags/" label="commitlint-gitlab-ci" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <category term="semantic-release" scheme="https://d.moonfire.us/tags/" label="semantic-release" />
    <category term="conventional-commits" scheme="https://d.moonfire.us/tags/" label="Conventional Commits" />
    <category term="commitlint" scheme="https://d.moonfire.us/tags/" label="commitlint" />
    <category term="husky" scheme="https://d.moonfire.us/tags/" label="Husky" />
    <summary type="html">Since I'm usually creating a new Git repo (about 3/month) and commitlint is one of the first things I set up, I ended up writing a little NPM utility to solve a bug that was causing me problems on Gitlab.
</summary>
    <content type="html">&lt;p&gt;I have a slowly evolving set of practices when it comes to writing processes. One of the first ones is setting up a Git repository. This always starts with configuring &lt;a href="https://typicode.github.io/husky/#/"&gt;husky&lt;/a&gt;, &lt;a href="https://semantic-release.gitbook.io/semantic-release/"&gt;semantic-release&lt;/a&gt;, &lt;a href="https://www.conventionalcommits.org/en/"&gt;conventional-commits&lt;/a&gt;, and &lt;a href="https://commitlint.js.org/#/"&gt;commitlint&lt;/a&gt;. (I'm working on updating my &lt;a href="https://www.npmjs.com/package/generator-mfgames-writing"&gt;Yeoman generator&lt;/a&gt; to make this a lot easier, but that will be later this week.)&lt;/p&gt;
&lt;p&gt;Sadly, my Git host of choice, &lt;a href="https://gitlab.com/"&gt;Gitlab&lt;/a&gt;, has a little problem with &lt;code&gt;commitlint&lt;/code&gt;. It blows up on the first few commits which lead to me reporting &lt;a href="https://github.com/conventional-changelog/commitlint/issues/885"&gt;this&lt;/a&gt; issue.&lt;/p&gt;
&lt;p&gt;Since I'm usually creating a number of new Git repositories in a month and &lt;code&gt;commitlint&lt;/code&gt; is one of the first things I set up, I ended up writing &lt;a href="https://www.npmjs.com/package/commitlint-gitlab-ci"&gt;a little NPM utility&lt;/a&gt; to handle the bug for me since the original package (rightfully, I feel) don't want to add Gitlab-specific code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx commitlint-gitlab-ci -x @commitlint/config-conventional
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems to work fairly well for me, I've been messing with it for a little while and haven't had too many complaints.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Gallium Nitride and Gemini</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2021/07/10/gallium-nitride-and-gemini/" />
    <updated>2021-07-10T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2021/07/10/gallium-nitride-and-gemini/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="statiq" scheme="https://d.moonfire.us/tags/" label="Statiq" />
    <category term="gallium" scheme="https://d.moonfire.us/tags/" label="Gallium" />
    <category term="mfgames-nitride" scheme="https://d.moonfire.us/tags/" label="MfGames.Nitride" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <category term="gemini" scheme="https://d.moonfire.us/tags/" label="Gemini" />
    <summary type="html">Last November, I switched my static site generator from CobblestoneJS (my homebrew Gulp-based one) to Statiq. There were a number of reasons, all of them still good but mainly to support what I want to do with fedran.com and my other sites. This weekend, I changed it to a new static site generator that I have written and hosted the site also on Gemini.
</summary>
    <content type="html">&lt;p&gt;Last &lt;a href="/blog/2020/11/20/website-update/"&gt;November&lt;/a&gt;, I switched my static site generator from CobblestoneJS (my homebrew Gulp-based one) to &lt;a href="https://statiq.dev/"&gt;Statiq&lt;/a&gt;. There were a number of reasons, all of them still good but mainly to support what I want to do with &lt;a href="https://fedran.com/"&gt;fedran.com&lt;/a&gt; and my other sites.&lt;/p&gt;
&lt;p&gt;This holiday weekend, I ended up ripping out all of the Statiq and wrote another static site generator, this time in C# and using an &lt;a href="https://en.m.wikipedia.org/wiki/Entity_component_system"&gt;Entity-Component-System&lt;/a&gt; (ECS). I also migrated my site over to &lt;a href="gemini://d.moonfire.us/"&gt;Gemini&lt;/a&gt; as part of the effort.&lt;/p&gt;
&lt;h1&gt;Why?&lt;/h1&gt;
&lt;p&gt;I liked many of the ideas that Statiq provided:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Treating the website generation as code.&lt;/li&gt;
&lt;li&gt;Having pipelines with dependencies for generation.&lt;/li&gt;
&lt;li&gt;Immutable objects on the pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, I found myself struggling with concepts. It just didn't sit well with me and I would spend two weeks trying to implement a feature and getting stuck. When I realized I had spent a month not fixing something that was bothering me because I didn't want to delve into the code, I knew it was time to change.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;That isn't to say Statiq isn't bad. It just isn't for me. That's it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;About once a year, I get 4-7 days of &amp;ldquo;alone time&amp;rdquo; to do what I want. This year, I decided to work on a new static site generator that did work the way I work today and that I hoped would carry me over for the next five years or so.&lt;/p&gt;
&lt;h1&gt;Entity-Component-Systems (ECS)&lt;/h1&gt;
&lt;p&gt;One thing that Statiq did (but differently) was implemented the system as an ECS. Basically, you have a lightweight object (the &amp;ldquo;entity&amp;rdquo;) and add various components into it. Those components are what provide the features: the text content, flags to say if it is HTML or Markdown, or the path.&lt;/p&gt;
&lt;p&gt;While Statiq had a number of these elements built-into the &lt;code&gt;Document&lt;/code&gt; call (basically their entity), there were a lot of assumptions that didn't always fit. Likewise, &lt;code&gt;Statiq.Web&lt;/code&gt; had some nice opinionated ways of handling it, including a document type (binary, text, etc), but I couldn't find an easy way to extend it.&lt;/p&gt;
&lt;h1&gt;Gallium&lt;/h1&gt;
&lt;p&gt;With my ECS, &lt;code&gt;Entity&lt;/code&gt; is only a collection plus an integer identifier. Components can be added, removed, and replaced easily using generics to determine the type. Methods are chained together but not pseudo-English fluent (which I'm also not fond of). Entities are immutable, so all the operations return a clone of that entity with the new components added, removed, or otherwise changed. (Thanks to functional programming for some of those ideas.)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;Entity entity = new();
Entity entityWithTwoComponents = entity
  .Set(new Uri(&amp;quot;https://d.moonfire.us&amp;quot;))
  .Set&amp;lt;FileSystemInfo&amp;gt;(new FileInfo(&amp;quot;/bob.txt&amp;quot;));
Entity entityWithReplacedUri = entityWithTwoComponents
  .Set(new Uri(&amp;quot;http://path-to-replace-d.moonfire.us/&amp;quot;));
Entity entityWithOnlyUri = entityWithReplacedUri
  .Remove&amp;lt;FileSystemInfo&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also really like chained operations, so most of the processing looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;IEnumerable&amp;lt;Entity&amp;gt; input;
var onlyHtmlOutputs = input
  .OrderBy(x =&amp;gt; x.Get&amp;lt;FileInfo&amp;gt;().FullPath)
  .ForComponents&amp;lt;Uri&amp;gt;((entity, uri) =&amp;gt; this.Uri(entity, uri))
  .WhereComponents&amp;lt;IsHtml&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The whole idea is &lt;code&gt;ForComponents&amp;lt;T1, T2, T3&amp;gt;&lt;/code&gt; will go through the list and for all entities that have &lt;code&gt;T1&lt;/code&gt;, &lt;code&gt;T2&lt;/code&gt;, and &lt;code&gt;T3&lt;/code&gt;, it will do the callback, otherwise it will passs it on. Likewise &lt;code&gt;WhereComponents&amp;lt;T1&amp;gt;&lt;/code&gt; is basically a &lt;code&gt;Where&lt;/code&gt; that says only the entities with the given components.&lt;/p&gt;
&lt;p&gt;Those ideas really simplified a lot of the difficulties I had with CobblestoneJS. Overall, most of the logic &amp;ldquo;felt&amp;rdquo; right for me, so I'm really happy with the results. Plus, it is based on a far more stable package ecosystem (NuGet) and in a language I enjoy greatly (C#).&lt;/p&gt;
&lt;p&gt;Also, the language uses &lt;a href="https://autofac.org/"&gt;Autofac&lt;/a&gt; as my preferred dependency injection of choice. I really like the library plus &lt;a href="https://nodatime.org/"&gt;NodaTime&lt;/a&gt; when coding, so I went with these. It's a bit opinionated, but&amp;hellip; only a few people ever used Cobblestone, so I'm going to assume very few are going to use this.&lt;/p&gt;
&lt;p&gt;Once I get it cleaned up, I'll probably call the ECS &amp;ldquo;Gallium&amp;rdquo; because my original name was &amp;ldquo;Gallium Nitride&amp;rdquo; (GaN, because it's a cool name and I like what the molecule does). The static site generator would be named Nitride.&lt;/p&gt;
&lt;h1&gt;Nitride&lt;/h1&gt;
&lt;p&gt;Nitride is just a multi-threaded pipeline static generator. It uses pipelines much like Statiq but based on C#'s thread control (&lt;code&gt;ManualReset&lt;/code&gt;, &lt;code&gt;ReaderWriterLockSlim&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The rough code looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;List&amp;lt;Entity&amp;gt; list = entities
    .Run(new IdentifyMarkdown())
    .Run(new ParseYamlHeader&amp;lt;PageModel&amp;gt;())
    .ForComponents&amp;lt;PageModel&amp;gt;(this.SetHandlebarsFromPageModel)
    .Run(this.setInstantFromComponent)
    .Run(this.filterOutFutureInstants)
    .Run(this.createCategoryIndexes)
    .Run(this.createTagIndexes)
    .ToList();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, DI or direct instantiate of modules, it all works the same and really ties into using Linq and C# generics. All of the pipelines are &lt;code&gt;async&lt;/code&gt; but most of the operations (&lt;code&gt;createTagIndexes&lt;/code&gt;, &lt;code&gt;ParseYamlHeader&lt;/code&gt;) are not. But since the pipelines are, it is easy to make something &lt;code&gt;await&lt;/code&gt; without changing signatures.&lt;/p&gt;
&lt;p&gt;I really like the pipelines. For my site, I have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PostsPipeline&lt;/code&gt;: Load posts and create blog archives&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PagesPipeline&lt;/code&gt;: Load static pages.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContentPipeline&lt;/code&gt;: Combines &lt;code&gt;PostsPipeline&lt;/code&gt; and &lt;code&gt;PagesPipeline&lt;/code&gt;, creates categories/tag indexes, handle filtering out future pages.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BareHtmlPipeline&lt;/code&gt;: Takes &lt;code&gt;ContentPipeline&lt;/code&gt; and converts into bare, unstyled HTML. Also creates the RSS and Atom feeds from the bare HTML.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WebpackPipeline&lt;/code&gt;: Runs Webpack.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StyledHtmlPipeline&lt;/code&gt;: Takes &lt;code&gt;BareHtmlPipeline&lt;/code&gt; and &lt;code&gt;WebpackPipeline&lt;/code&gt; and makes it styled using handlebars.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GeminiPipeline&lt;/code&gt;: Takes &lt;code&gt;ContentPipeline&lt;/code&gt; and turns the Markdown into Gemini, applies some simple styling, and generates Gemtext pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's it, but I'm happy with the result because I've taken lessons learned from my previous attempts to created something that will handle Fedran's massive cross-linking and project pages, MfGames's pulling in of separate Git repositories, and also some of the more complex formatting of my new sci-fi fiction website.&lt;/p&gt;
&lt;h1&gt;Gemini&lt;/h1&gt;
&lt;p&gt;I like the idea of &lt;a href="//gemini.circumlunar.space/"&gt;Gemini&lt;/a&gt;. It is a low-overhead protocol that has almost no extra features, no cookies, and basically focused on presenting content. In my case, I really want to see all of my sites on Gemini because I think it has some significant merits, more so as I want to get away from heavily styled content written by people who like tiny fonts or don't have my color contrast issues.&lt;/p&gt;
&lt;p&gt;To do that, I ended up taking inspiration from &lt;a href="https://pypi.org/project/md2gemini/"&gt;md2gemini&lt;/a&gt; and wrote a C# library that converts Markdown into Gemtext (Gemini's markup format inspired by Markdown). The end result is &lt;a href="gemini://d.moonfire.us/"&gt;pretty nice&lt;/a&gt;, I think and I'm really happy with the results.&lt;/p&gt;
&lt;p&gt;Of course, it meant I had to get a virtual machine to host a Gemini server next to a HTTP one, but that was going to happen sooner or later anyways.&lt;/p&gt;
&lt;h1&gt;Next Steps&lt;/h1&gt;
&lt;p&gt;I write a lot libraries that I think are interesting but very few people worry about. They rise up, either I stick with them or I trail off, but they always scratch my itches. On that front, the following things are left to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Split out Gallium more formally into &lt;code&gt;MfGames.Gallium&lt;/code&gt; or &lt;code&gt;Gallium&lt;/code&gt;, not sure.&lt;/li&gt;
&lt;li&gt;Clean up the API for &lt;code&gt;Nitride&lt;/code&gt; and make sure everything is consistent. Some of the names are a bit&amp;hellip; off, but the functionality is good.&lt;/li&gt;
&lt;li&gt;Break all the modules into separate Gitlab projects and set up CI for releasing.&lt;/li&gt;
&lt;li&gt;Document everything.&lt;/li&gt;
&lt;li&gt;Convert five other websites sites to use it to figure out what is missing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven't found the money to get a developer's signing certificate, so I'll probably just put everything up on my public &lt;a href="https://www.myget.org/"&gt;MyGet repository&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>March in Writing</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2020/04/01/month-in-writing/" />
    <updated>2020-04-01T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2020/04/01/month-in-writing/</id>
    <category term="writing" scheme="https://d.moonfire.us/categories/" label="Writing" />
    <category term="writing-summary" scheme="https://d.moonfire.us/tags/" label="Writing Summary" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">A summary of a March worth of writing. It was a hard month but I still got three stories in addition to my chapters. And hit a major roadblock
</summary>
    <content type="html">&lt;p&gt;This was a rough month. As pretty much everyone knows, COVID-19 is throwing wrenches into everyone's plans. Between the anxiety of a pandemic, having children at home, and the regular disruptions to my schedules, writing has been difficult. Oh well, I'm going to adapt like everything else.&lt;/p&gt;
&lt;p&gt;I'm still maintained my weekly chapter posting. I managed to get a six week buffer though it's down to two weeks at this point due to distractions of various natures (the big one is below). March covered consecutive weeks 245 through 249 of my weekly chapter goal so I'm excited that I'm halfway done through the 200s.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fedran.com/allegro/"&gt;Allegro&lt;/a&gt; 11-15: I'm really enjoying this part of the story. It is the early days of Linsan on her own, mainly about those first days of being on her own and the frustrations of trying to find the murderers and thieves.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the short story side, I had three at the end of the month:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fedran.com/illusions-of-the-dead/story/"&gt;Illusions of the Dead&lt;/a&gt; was a inspired by &lt;a href="https://victoriacorva.xyz"&gt;Victoria Corva&lt;/a&gt;. This is another of the stories about the dead of the world, but not undead. In this case, it is about an illusionist giving someone closer.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fedran.com/confessions-among-friends/story/"&gt;Confessions Among Friends&lt;/a&gt; is a short story about two old men who find out they were on opposite sides of the same war.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fedran.com/brilliant-luck/story/"&gt;Brilliant Luck&lt;/a&gt; is the sequel to a flash fiction I wrote a while ago, &lt;a href="https://fedran.com/brilliant-manifestation/story/"&gt;Brilliant Manifestation&lt;/a&gt;. Told from the point of view of a father (Jacom) who's son had gotten light powers (one of the rarer forms of magic in my world), it is just another view of a parent seeing how their child changes after going away for a year. (Something that I'll probably go through myself, not sure).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last year, I did a poem a day for National Poetry Month. As much as I'd like to do that, I'm thinking it is too much load at this point. Likewise, I have given up trying to write a money post this year. I'm also going to skip writing processes post, but maybe only for a month or two.&lt;/p&gt;
&lt;p&gt;On the other hand, I did hit a lovely distraction. About a week ago, my &lt;a href="https://gitlab.com/fedran/fedran-website/"&gt;Gitlab&lt;/a&gt; stopped deploying. I have no clue what changed and I spent two days trying to figure it out without any success. This was based on a static site generator I had written (Cobblestone) but I decided to try switching over Fedran's (no other site has a problem) to &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The last time I tried Gatsby, it was a disaster. It took seven hours to generate the website after three days of trying. This time, however, it has been going much faster and I've been rather happy with the results. I'm about 19% done with the conversion, but I'm aiming for having a limited version of the site on &lt;a href="https://fedran.com/"&gt;https://fedran.com/&lt;/a&gt; by the end of Sunday.&lt;/p&gt;
&lt;p&gt;It doesn't hurt that I understand CSS Grid and Flexbox a lot better, so a lot of the hoops I had jumped through are much easier. However, I have years of custom code behind this website so it will take a while to produce a good looking and useful site.&lt;/p&gt;
&lt;p&gt;In April, my goals are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continue &lt;em&gt;Allegro&lt;/em&gt; and get a few more weeks buffer going.&lt;/li&gt;
&lt;li&gt;Three short stories.&lt;/li&gt;
&lt;li&gt;Get the 80% point on the Fedran website conversion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As usual, let me know if you like any stories or want to see new topics or themes. I'm deeply thankful for my subscribers through &lt;a href="https://patreon.com/dmoonfire"&gt;Patreon&lt;/a&gt; and &lt;a href="https://fedran.com/patrons/"&gt;other places&lt;/a&gt;. Your help has been wonderful in encouraging me.&lt;/p&gt;
&lt;p&gt;Thank you.&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>Working with MfGames Writing, CI, and Docker</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2018/08/24/mfgames-writing-docker-and-ci/" />
    <updated>2018-08-24T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2018/08/24/mfgames-writing-docker-and-ci/</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="docker" scheme="https://d.moonfire.us/tags/" label="Docker" />
    <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="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">How to use a continual integration (CI) server to publish projects.
</summary>
    <content type="html">&lt;p&gt;One of the main points of having &lt;a href="/tags/mfgames-writing/"&gt;MfGames Writing&lt;/a&gt; is to automate the publication process.&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;Working with MfGames Writing, CI, and Docker: 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;Adding Scripts&lt;/h1&gt;
&lt;p&gt;We've installed the commands in a previous step, but hooking them up in the &lt;code&gt;package.json&lt;/code&gt; makes life a lot easier.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;test-project&amp;quot;,
  &amp;quot;private&amp;quot;: true,
  &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;build:epub&amp;quot;: &amp;quot;mfgames-writing-format build epub&amp;quot;,
    &amp;quot;build:pdf&amp;quot;: &amp;quot;mfgames-writing-format build pdf&amp;quot;,
    &amp;quot;build:html&amp;quot;: &amp;quot;mfgames-writing-format build html&amp;quot;,
    &amp;quot;build:docx&amp;quot;: &amp;quot;sed 's@&amp;amp;#173;@@g' &amp;lt; $npm_package_name-$npm_package_version.html | pandoc -f html -t docx -o $npm_package_name-$npm_package_version.docx&amp;quot;,
    &amp;quot;build:mobi&amp;quot;: &amp;quot;kindlegen $npm_package_name-$npm_package_version.epub&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;npm run build:epub &amp;amp;&amp;amp; npm run build:mobi &amp;amp;&amp;amp; npm run build:pdf &amp;amp;&amp;amp; npm run build:html &amp;amp;&amp;amp; npm run build:docx&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically this sets up my basic suite of scripts that let me generate everything or one specific file.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ npm run build:epub
$ npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see we use a couple other programs like &lt;code&gt;pandoc&lt;/code&gt; to make DOCX files from HTML or MOBI files using the EPUB file and &lt;code&gt;kindlegen&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I use &lt;code&gt;$npm_package_name&lt;/code&gt; to pull in the package name (as I said, I use them for consistency) which lets me produce files with a consistent pattern including the version number.&lt;/p&gt;
&lt;p&gt;The other formats (HTML, PDF, etc) will be talked about in &lt;a href="/blog/2018/08/25/mfgames-writing-formats/"&gt;tomorrow's post&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;CI Configuration&lt;/h1&gt;
&lt;p&gt;I use &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt; as my primary development platform. I like the company, the fact they open-source much of their code, and their features. Most important is that they provide private repos, which means I can have one repo for every novel I work on.&lt;/p&gt;
&lt;p&gt;GitLab has a continual integration (CI) service which will automatically run whenever I push up code. This is controlled by the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;# This Docker image contains all the libraries and tools to generate files.
image: dmoonfire/mfgames-writing-js:1.1.1

stages:
    - publish

publish:
    stage: publish
    tags:
        - docker

    # Generate the various publication files.
    script:
        - npm ci
        - npm run build

    # Keeping artifacts means we can download them after the fact.
    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;If CI is turned on in GitLab and this file is present, then it will automatically run the commands in the &lt;code&gt;script&lt;/code&gt; section. It then takes the resulting PDF, EPUB, MOBI, DOCX, and HTML files and zips them up to be found on the website. Basically this runs the same command that you can run manually which makes it easier to test.&lt;/p&gt;
&lt;p&gt;&lt;a href="/blog/2018/08/mfgames-writing-download.png"&gt;&lt;img class="img-responsive post-img-link" src="/blog/2018/08/mfgames-writing-download.png" alt="Download Button" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Docker&lt;/h1&gt;
&lt;p&gt;In the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file, you may notice we use a Docker image &lt;code&gt;dmoonfire/mfgames-writing-js:1.1.1&lt;/code&gt;. This is up on &lt;a href="https://hub.docker.com/r/dmoonfire/mfgames-writing-js/"&gt;DockerHub&lt;/a&gt; and includes the various programs and utilities needed to generate the files. Some of the formats, in specific &lt;a href="https://weasyprint.org/"&gt;WeasyPrint&lt;/a&gt;, have specific installations and I found that having a Docker image makes life a lot easier.&lt;/p&gt;
&lt;p&gt;The image contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NPM and required packages&lt;/li&gt;
&lt;li&gt;WeasyPrint&lt;/li&gt;
&lt;li&gt;KindleGen&lt;/li&gt;
&lt;li&gt;Pandoc&lt;/li&gt;
&lt;li&gt;PdfTk (pdfcat)&lt;/li&gt;
&lt;/ul&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>
  <entry>
    <title>MfGames Tasks v0.0</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2018/02/23/mfgames-tasks/" />
    <updated>2018-02-23T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2018/02/23/mfgames-tasks/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="mfgames-tasks" scheme="https://d.moonfire.us/tags/" label="MfGames Tasks" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">To combat being overwhelmed by my many projects and obligations, I wrote a little tool to aggregate my todo lists across GitLab and GitHub.
</summary>
    <content type="html">&lt;p&gt;As some of you know, I have a lot of irons in the fire. Some of them are the natural problem of programmers where many interesting things never take root but sometimes there are a few that do and they quickly blossom in needing more time. In other cases, it is commissions due, weekly chapters, and the normal household to do list.&lt;/p&gt;
&lt;p&gt;I keep most of my issues in &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt; including things I have to do for sales tax, filing dates, and even per-project items. I also keep my novels and commissions there, along with associated issues to keep each moving.&lt;/p&gt;
&lt;p&gt;So, when I get stressed out, I write things to help me. In this case, I decided to write &lt;code&gt;mfgames-tasks&lt;/code&gt; which pulls all of those assigned issues and throws it into a single Markdown file which I keep on Dropbox across all my machines. This way, it picks up the items from each of those repositories and jams it into a file that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-markdown"&gt;# dmoonfire / mfgames-culture-js

-   Errors representing some seconds and milliseconds
    -   https://api.github.com/repos/dmoonfire/mfgames-culture-js/issues/3

# dmoonfire / mfgames-locking-cil

-   [simple] Add/update unit tests
    -   https://gitlab.com/dmoonfire/mfgames-locking-cil/issues/2
-   [simple] Get this packaged and uploaded to NuGet
    -   https://gitlab.com/dmoonfire/mfgames-locking-cil/issues/1

# typewriter-press / events

-   {2018-08-30} Register as an attendee
    -   https://gitlab.com/typewriter-press/events/issues/2
-   {2018-03-30} Register as a vendor and get a table
    -   https://gitlab.com/typewriter-press/events/issues/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It handles due dates (in &lt;code&gt;{2018-03-30}&lt;/code&gt;) and labels (such as &lt;code&gt;[simple]&lt;/code&gt;). If there are none, it skips them. On GitLab, if the issue is assigned to a milestone and doesn't have a due date of its own, it uses the milestone's due date.&lt;/p&gt;
&lt;p&gt;Another big feature is that GitLab issues that are assigned to a milestone that hasn't started, it doesn't include them. This lets me set up quarterly or monthly milestones (e.g., taxes) and have them pop up when they are needed.&lt;/p&gt;
&lt;h1&gt;Installation&lt;/h1&gt;
&lt;p&gt;I wrote this in Typescript because I really like it as a scripting language and it has a nice ecosystem. Installation is pretty simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;npm install --global mfgames-tasks-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Configuration&lt;/h1&gt;
&lt;p&gt;As my preferred configuration file format, I have a &lt;code&gt;mfgames-tasks.yaml&lt;/code&gt; file on my laptop. It looks somewhat like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;# This is what defines the sources to scan for outstanding tasks.
sources:
    - id: github-dmoonfire
      type: github
      token: TOKEN # Get from GitHub settings
    - id: gitlab-dmoonfire
      type: gitlab
      token: TOKEN # Get from GitLab settings
    # You can have multiple GitLab and GitHub accounts.

# This defines how the files are written out. There is only one choice and it doesn't have formatting.
outputs:
    - type: markdown
      id: md
      path: /path/to/output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the above file, I just have this added to my hourly cron:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;mfgames-tasks write path/to/mfgames-tasks.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Documentation&lt;/h1&gt;
&lt;p&gt;Yeah, there isn't a lot of documentation here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/dmoonfire/mfgames-tasks-js-cli"&gt;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/mfgames-tasks-cli"&gt;NPM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, to work on the 332 lines of items on my list.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>NaNoGenMo, ICON, New Laptop, and NSFW Second-Hand Dresses 19</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2017/10/04/second-hand-dresses-19/" />
    <updated>2017-10-04T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2017/10/04/second-hand-dresses-19/</id>
    <category term="writing" scheme="https://d.moonfire.us/categories/" label="Writing" />
    <category term="fedran" scheme="https://d.moonfire.us/tags/" label="Fedran" />
    <category term="second-hand-dresses" scheme="https://d.moonfire.us/tags/" label="Second-Hand Dresses" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">I had some technical difficulties this week, so it is a short posting again. This week, Lily is happily working on her dress when she is interrupted once again. This time, it is from Margiold who is in a fury because her daughter's dress isn't done weeks before it was done. Unreasonable? Probably. However when Lily breaks down, she finds comfort from an unexpected source.</summary>
    <content type="html">&lt;p&gt;I had some technical difficulties this week, so it is a short posting again. This week, Lily is happily working on her dress when she is interrupted once again. This time, it is from Margiold who is in a fury because her daughter's dress isn't done weeks before it was done. Unreasonable? Probably. However when Lily breaks down, she finds comfort from an unexpected source.&lt;/p&gt;
&lt;h1&gt;NaNoGenMo&lt;/h1&gt;
&lt;p&gt;My plans to enjoy &lt;a href="https://github.com/NaNoGenMo/2017/issues/12"&gt;NaNoGenMo&lt;/a&gt; might be in jeopardy. Over the convention, I had a series of expensive problems (laptop got destroyed, car's oil pain got cracked) so I might have to focus on completing more commissions. That will suck away the energy I have to do NaNoGenMo, which is heartbreaking. However, I have to be &amp;ldquo;responsible&amp;rdquo; before having fun; that is what I keep telling my boy.&lt;/p&gt;
&lt;p&gt;I won't have a laptop until Wednesday at the earliest which means I won't be able to write anything until then. Thursday is my writing group night so&amp;hellip; nothing for almost an entire week. We'll find out, but if it comes to push, I have to do obligations first. The cool part is that I'm writing this blog post off &lt;a href="https://gitlab.com/"&gt;Gitlab&lt;/a&gt; and the CI setup I've been using does all the rest.&lt;/p&gt;
&lt;h1&gt;New Laptop&lt;/h1&gt;
&lt;p&gt;I am excited about the new laptop. I haven't had one in about eight years. While it was a 17&amp;quot; with a large keyboard, it wasn't large enough for me. This time, I'm trying a &lt;em&gt;2 in 1&lt;/em&gt; that folds back and then also bought a ten keyless Cherry Brown mechanical keyboard which should make it more comfortable when I get up to my full typing speeding. Anything around 100 wpm starts to cause me a lot of pain. The monitor is small but I'm hoping that it will work out if my wrists don't hurt as much.&lt;/p&gt;
&lt;h1&gt;ICON&lt;/h1&gt;
&lt;p&gt;Baring the above bad news, ICON was a fun convention. I got to chat with a lot of people and maybe made a few fans. My reading wasn't really attended (my wife and a good friend came but no one else) so the bump in book sales didn't quite happen. I am happy to see that my new covers were pretty much universally preferred over the old one.&lt;/p&gt;
&lt;h1&gt;NSFW&lt;/h1&gt;
&lt;p&gt;This chapter isn't &lt;em&gt;that&lt;/em&gt; raunchy but there are a couple details that probably aren't work-friendly. After Lily breaks down, someone comes to her rescue from an unexpected quarter and Lily is thrust into a position where her fantasties become a bit more real, not to mention her hopes are confirmed as she is comforted from the abuse.&lt;/p&gt;
&lt;h1&gt;Second-Hand Dresses 19: Fury&lt;/h1&gt;
&lt;p&gt;Once again, Lily finally gets into the groove of working on the dresses when Marigold comes in, furious and ready to fight. Despite Lily's attempt to placate her, the far more powerful woman rants about Lily's skill and effort because Lily has not been working exclusively on Nirih's dress. When she leaves, Lily is in tears.&lt;/p&gt;
&lt;p&gt;Read the chapter at &lt;a href="https://fedran.com/second-hand-dresses/chapter-19/"&gt;https://fedran.com/second-hand-dresses/chapter-19/&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Patrons&lt;/h1&gt;
&lt;p&gt;My completed works and various works-in-progress are available for free on my &lt;a href="https://fedran.com/"&gt;fantasy website&lt;/a&gt;. If you like what you've read and want to see more, consider becoming a &lt;a href="https://fedran.com/patrons/"&gt;patron&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>State of writing with Markdown, YAML, and Git 2017</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2017/05/24/git-and-writing/" />
    <updated>2017-05-24T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2017/05/24/git-and-writing/</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="wiscon" scheme="https://d.moonfire.us/tags/" label="Wiscon" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">A year ago, at one of my more successful panels at [WisCon](http://wiscon.info/), I was on a panel with [K. Tempest Bradford](https://tempest.fluidartist.com/find-a-tempest-wiscon-40/) and [Kristine Smith](http://www.kristine-smith.com/index.php/2016/05/home-5/) talking about writing processes. I got to see a lot of cool gadgets but I also got a chance to talk about my processes of writing with Markdown, YAML, and Git.</summary>
    <content type="html">&lt;p&gt;A year ago, at one of my more successful panels at &lt;a href="http://wiscon.info/"&gt;WisCon&lt;/a&gt;, I was on a panel with &lt;a href="https://tempest.fluidartist.com/find-a-tempest-wiscon-40/"&gt;K. Tempest Bradford&lt;/a&gt; and &lt;a href="http://www.kristine-smith.com/index.php/2016/05/home-5/"&gt;Kristine Smith&lt;/a&gt; talking about writing processes. I got to see a lot of cool gadgets but I also got a chance to talk about my processes of writing with Markdown, YAML, and Git.&lt;/p&gt;
&lt;p&gt;I'm not going to WisCon this year, but I thought this would be a good opportunity to write up where I am using all those technologies to write, both for my personal projects and as a &lt;a href="https://broken.typewriter.press/"&gt;publisher&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a long post in a single part. If you've read my blog, there is some rehashed information.&lt;/p&gt;
&lt;h1&gt;Markdown and YAML&lt;/h1&gt;
&lt;p&gt;Probably the one part that hasn't changed is my use of &lt;a href="https://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt; and &lt;a href="http://yaml.org/"&gt;YAML&lt;/a&gt;. I originally used Creole with a makeshift header but after playing with &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; for a while, I jumped whole-heartedly on Markdown with a YAML header.&lt;/p&gt;
&lt;p&gt;Below is an example of one of the files. I'll be referencing it a bit in this post so please forgive the length.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
availability: public
when: 1471/3/28 MTR
duration: 25 gm
date: 2012-02-18
title: Rutejìmo
locations:
  primary:
    - Shimusogo Valley
characters:
  primary:
    - Shimusogo Rutejìmo
  secondary:
    - Shimusogo Hyonèku
  referenced:
    - Funikogo Ganósho
    - Shimusogo Gemènyo
    - Shimusogo Chimípu
    - Shimusogo Yutsupazéso
concepts:
  referenced:
    - The Wait in the Valleys
purpose:
  - Introduce Rutejìmo
  - Introduce Hyonèku
  - Introduce naming conventions
  - Introduce formality rules
  - Introduce the basic rules of politeness
summary: &amp;gt;
  Rutejìmo was on top of the clan's shrine roof trying to sneak in and steal his grandfather's ashes. It was a teenage game, but also one to prove that he was capable of becoming an adult. He ended up falling off the roof.

  The shrine guard, Hyonèku, caught him before he hurt himself. After a few humiliating comments, he gave Rutejìmo a choice: tell the clan elder or tell his grandmother. Neither choice was good, but Rutejìmo decided to tell his grandmother.
---

&amp;gt; When a child is waiting to become an adult, they are subtly encouraged to prove themselves ready for the rites of passage. In public, however, they are to remain patient and respectful. --- Funikogo Ganóshyo, *The Wait in the Valleys*

Rutejìmo's heart slammed against his ribs as he held himself still. The cool desert wind blew across his face, teasing his short, dark hair. In the night, his brown skin was lost to the shadows, but he would be exposed if anyone shone a lantern toward the top of the small building. Fortunately, the shrine house was at the southern end of the Shimusogo Valley, the clan's ancestral home, and very few of the clan went there except for meetings and prayers.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I seem to be moving from the &lt;code&gt;.markdown&lt;/code&gt; to &lt;code&gt;.md&lt;/code&gt; extension. It's minor but I haven't quite jumped on it; I've only done it for the last two new projects.&lt;/p&gt;
&lt;h1&gt;Atom&lt;/h1&gt;
&lt;p&gt;My current editor of choice for novels is &lt;a href="https://atom.io/"&gt;Atom&lt;/a&gt; with a backup of Emacs. Unlike Emacs, Atom has standard keyboards and looks good with the fonts I use. It is a little slow, but for the most part, works pretty well for belting out words.&lt;/p&gt;
&lt;p&gt;I'm writing some extensions for it including a modified spell check (&lt;code&gt;project-spell&lt;/code&gt;) that can handle project-specific dictionaries (&lt;code&gt;language.json&lt;/code&gt;). This lets me tell the spell-checker not to mark character names as misspelled.&lt;/p&gt;
&lt;p&gt;Later, I'll integrate my work into Author Intrusion with this but that isn't nearly ready for prime time even for my purposes.&lt;/p&gt;
&lt;h1&gt;Metadata&lt;/h1&gt;
&lt;p&gt;Over the last year I noticed I am putting lot more information in the header than before. Some of it is done long after the project but even while writing, I'll put in notes about the characters, the reason I'm writing the chapter, time of day, even the outline which I remove as I write.&lt;/p&gt;
&lt;p&gt;I just redid the &lt;a href="https://fedran.com/"&gt;Fedran&lt;/a&gt; website, otherwise I'd show you how the &lt;code&gt;characters&lt;/code&gt; and related fields show up in the sidebar. I'll get that worked in the next few months, but it let me cross-link things into my wiki. Having it in the header also means I can query it to get a summary of the page using a TypeScript tool I wrote called &lt;a href="https://www.npmjs.com/package/markdowny"&gt;markdowny&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ markdowny table *.markdown -f _basename title when
| _basename           | title                   | when          |
| :------------------ | :---------------------- | :------------ |
| chapter-01.markdown | Rutejìmo                | 1471/3/28 MTR |
| chapter-02.markdown | Confession              | 1471/3/28 MTR |
| chapter-03.markdown | Morning                 | 1471/3/29 MTR |
| chapter-04.markdown | Rivals                  | 1471/3/29 MTR |
| chapter-05.markdown | Decisions               | 1471/3/29 MTR |
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another nice thing about &lt;code&gt;markdowny&lt;/code&gt; is that it also lets me show those YAML lists in a useful manner.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ markdowny table -f _basename characters.secondary
| _basename           | characters.secondary
| :------------------ | :-------------------------------------------------
| chapter-01.markdown | Hyonèku
| chapter-02.markdown | Somiryòki, Tejíko, Gemènyo
| chapter-03.markdown | Desòchu, Gemènyo, Hyonèku, Mapábyo, Opōgyo, Panédo
| chapter-04.markdown | Desòchu, Karawàbi, Tsubàyo
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also has writing synopsis at the end, so what I can do is put each individual chapter in its header (in my case &lt;code&gt;summary&lt;/code&gt;) and then use &lt;code&gt;markdowny&lt;/code&gt; to pull them out. That way, I can write the synopsis as I go and not be overwhelemed at the end.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ markdowny sections *.markdown | head -n 5
# Rutejìmo

Rutejìmo was on top of the clan's shrine roof trying to sneak in and steal his grandfather's ashes. It was a teenage game, but also one to prove that he was capable of becoming an adult. He ended up falling off the roof.

The shrine guard, Hyonèku, caught him before he hurt himself. After a few humiliating comments, he gave Rutejìmo a choice: tell the clan elder or tell his grandmother. Neither choice was good, but Rutejìmo decided to tell his grandmother.
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final bit is word counting. Because of the YAML metadata, I can't get good word counts using most tools becaues the header skews the number. So I use the tool to get me counts of the content minus the YAML header.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ markdowny count *.markdown
chapter-01.markdown:   1520
chapter-02.markdown:   2144
chapter-03.markdown:   2905
chapter-04.markdown:   1173
chapter-05.markdown:   2570
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also have an alias for &lt;code&gt;mdwc&lt;/code&gt; to the count since I use it pretty heavily.&lt;/p&gt;
&lt;h1&gt;Directory Structure&lt;/h1&gt;
&lt;p&gt;I'm leaning toward a semi-standard layout for my projects. Some of this was built up over the last few years but even my short stories have been migrating over to it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;root&gt;
  * `README.md` contains a summary of the project and my tasks list.
  * `chapters/` contains all the chapters in `chapter-01.md`. I have never had a project with more than 89 chapters, so I stick with two digit zero pad so it remains alphabetical.
  * `frontmatter/` contains the frontmatter (dedication, legal) files.
  * `backmatter/` contains the backmatter (colophon, about, also by).
  * `characters/` has one Markdown file per character, for future use with [Author Intrusion](/tags/author-intrusion/).
  * `covers/v1`: The first variant of the cover. I have a couple and each one goes into a different `vX` folder so I can keep them apart.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even with short stories, I have a &lt;code&gt;chapters/&lt;/code&gt; folder. I'm just picking up a &amp;ldquo;muscle memory&amp;rdquo; of going into chapters. I consider switching to putting things into a &lt;code&gt;src/&lt;/code&gt; like most of my programming projects I just haven't because I couldn't see the advantage other than having a neat folder.&lt;/p&gt;
&lt;h1&gt;Renumbering&lt;/h1&gt;
&lt;p&gt;One drawback of having &lt;code&gt;chapter-01.md&lt;/code&gt;, &lt;code&gt;chapter-02.md&lt;/code&gt;, etc is when I have to add a new chapter. I wrote a &lt;code&gt;renumber&lt;/code&gt; script that lets me inject a chapter.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ ls -l
total 8
-rw-r--r-- 1 dmoonfire dmoonfire  22 May 24 08:06 chapter-01.md
-rw-r--r-- 1 dmoonfire dmoonfire 127 May 24 08:06 chapter-02.md
$ touch chapter-01a.md
$ renumber *.md
$ ls -l
total 8
-rw-r--r-- 1 dmoonfire dmoonfire   0 May 24 08:07 chapter-01.md
-rw-r--r-- 1 dmoonfire dmoonfire  22 May 24 08:06 chapter-02.md
-rw-r--r-- 1 dmoonfire dmoonfire 127 May 24 08:06 chapter-03.md
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, using &lt;code&gt;01a&lt;/code&gt; puts it before the first chapter. It works the same with deleting chapters. Sadly, this script isn't very clean but eventually I'll merge it into &lt;code&gt;markdowny&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Git&lt;/h1&gt;
&lt;p&gt;One of the biggest advantages of using Markdown (text files in general) is how well is plays with source control, Git in specific. I can't stress how much Git has helped me over the years. I still remember accidentally losing a chapter because I copied the wrong file in the wrong direction. Or the painful way of tracking versions (&lt;code&gt;chapter-01a.doc&lt;/code&gt;, &lt;code&gt;chapter01b.doc&lt;/code&gt;, &lt;code&gt;chapter-01b-final.doc&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;At one point, I had a single master repository which all completed pieces in the &lt;code&gt;master&lt;/code&gt; branch and branches off that for the works-in-progress. That actually worked out pretty well&amp;hellip; until I started publishing. While working with text is great, the binary files of working through the covers ended up creating huge repositories which took forever to clone.&lt;/p&gt;
&lt;p&gt;Last year, I hadn't quite split apart all of my repositories but that's pretty much done now. This also meant I can give access to editors and others to a single novel without exposing the other ones. I don't have to worry about Git modules or jumping through hoops to have the binaries.&lt;/p&gt;
&lt;p&gt;I tried LFS (large file system) for a while but then dropped it. With it not baked in, it was a little difficult to coordinate with continuous integration servers. I think in another year or so, it could work out fairly well. I also suspect it has to do with my comfort with LFS more than technical issues.&lt;/p&gt;
&lt;h1&gt;Gitlab&lt;/h1&gt;
&lt;p&gt;Related to LFS is where I'm hosting Git. A year ago, I used Git over SSH with my ISP. However, &lt;a href="https://gitlab.com/"&gt;Gitlab&lt;/a&gt; has been fantastic, both as their hosted environment and also on an instance running on Dreamhost (my provider). There are a lot of reasons to use Gitlab as a writer (and a publisher).&lt;/p&gt;
&lt;p&gt;Probably the biggest is private repositories. Even if I didn't how it on my own site, being able to make each of the novels private is &lt;em&gt;fantastic&lt;/em&gt;. Github, which is only slightly slicker, doesn't allow private repositories. Even if they did, I have over a hundred projects when you count works-in-progress, completed novels, and websites. Hosting that on Github would be expensive.&lt;/p&gt;
&lt;p&gt;I also have a Gitlab instance. The &lt;a href="https://broken.typewriter.press/"&gt;Broken Typewriter Press&lt;/a&gt; business and my private novels on there. This gives me full control over the site (though I trust Gitlab) and I like it. The only people on the site are me, authors, and editors.&lt;/p&gt;
&lt;p&gt;Like Github, Gitlab has some pretty nice features. When publishing the last few books, we've used the issue tab for authors to ask for me to order books or make corrections to their book. I can give them access to make their own typo corrections, which reduces the amount of work. At the same time, because of Git, I can be doing other changes and I don't have to worry about losing or screwing up their work. For the latest book, &lt;em&gt;Sins of Intent&lt;/em&gt;, the author did a fantastic job of using the features.&lt;/p&gt;
&lt;p&gt;I use the milestones for the various tasks of publishing a book. That way I can set up milestones for when the book has to be done, when the release it done, and various conventions. The issues are assigned to the milestones for both the author and myself and we can track what is missing or remaining to do. In effect, we can use a public project management to handle a book's release.&lt;/p&gt;
&lt;p&gt;I normally turn off wiki and snippets though, they usually don't help.&lt;/p&gt;
&lt;p&gt;One of the things with using Gitlab this way is that the author has full access to the raw files. Typically, I get a Word document and break it into individual Markdown files. Corrections are done against the Markdown as my baseline format for everything else. If they want to leave BTP or something catastropic happens, they can have exactly what I published. This is because I've been through cases where local edits were made but I couldn't get them back myself. In this case, they get and can see everything I do.&lt;/p&gt;
&lt;p&gt;Which leads to the last feature of Gitlab which I use heavily, their Continious Integration service. This was difficult to set up at first, mainly because I had to educate myself. For most novels, the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;image: dmoonfire/mfgames-writing-js:0.4.0

stages:
    - review
    - publish

review:
    stage: review
    only:
        - master
    tags:
        - docker
    script:
        - git lfs pull # Yeah, I'm using LFS with this project.
        - npm install
        - npm run build
    artifacts:
        expire_in: 1 week
        paths:
            - &amp;quot;*.pdf&amp;quot;
            - &amp;quot;*.epub&amp;quot;
            - &amp;quot;*.mobi&amp;quot;

publish:
    stage: publish
    script: &amp;quot;echo published&amp;quot;
    when: manual
    artifacts:
        paths:
            - &amp;quot;*.pdf&amp;quot;
            - &amp;quot;*.epub&amp;quot;
            - &amp;quot;*.mobi&amp;quot;
    dependencies:
        - review
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every time I check in, this rebuilds the project. For the little changes, the &amp;ldquo;staging&amp;rdquo; lets me and authors test the results of the file which show up underneath the build. They expire after a week but that's okay. &amp;ldquo;Releases&amp;rdquo; are done by moving a task to &amp;ldquo;publish&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The nice part is I can grab the resulting PDF, MOBI, and PDF about 5-10 minutes after I check in. This is good to ensure that not only I have a reproducible build and also that I won't lost the ability to recover the output if my laptop catches on fire (it is almost seven years old, four majors cracks, and has a hernia).&lt;/p&gt;
&lt;p&gt;This ability to see the final version is great because me or another author can make changes and see it, test it, and make sure it is exactly what they want. If I change formatting, I can see the results without overloading my computer.&lt;/p&gt;
&lt;h1&gt;mfgames-writing-js&lt;/h1&gt;
&lt;p&gt;Of course, using CI requires some way of actually formatting the books. Markdown is fantastic for some things but there are relatively few tools to format it into good-looking EPUB, MOBI, and PDF files.&lt;/p&gt;
&lt;p&gt;Over the years, I have &lt;em&gt;many&lt;/em&gt; variants of this. The original few were based on Makefiles and various Python or Perl tools. I've also integrated &lt;a href="http://pandoc.org/"&gt;pandoc&lt;/a&gt; into the mix. Nothing ever worked &lt;em&gt;quite&lt;/em&gt; the way I wanted for what I considered to be a &amp;ldquo;proper&amp;rdquo; book. Files were put in the wrong place, dedications don't need titles, making sure chapters start on the right. There were little things that pushed me closer to making something more specific.&lt;/p&gt;
&lt;p&gt;I also had a problem that extending the features for a later book broke the generation of older books. I had to start over or rebuild (usually copy/paste/edit). Now this is a problem that has been addressed by NuGet and NPM, having the build process inside the project instead of using shared programs and libraries.&lt;/p&gt;
&lt;p&gt;Between this and using Gitlab CI runner, I decided to create a new framework that specifically was geared toward having specific versions that could be used to reproduce the book even if the underlying libraries were updated. I ended up using NPM, mainly because I'm learning TypeScript for the last few months. It also had a better story for installing (&lt;code&gt;npm install&lt;/code&gt;), wasn't whitespace-based, and specifically designed to be isolated to the project.&lt;/p&gt;
&lt;p&gt;The result is &lt;a href="https://gitlab.com/mfgames-writing-js"&gt;mfgames-writing-js&lt;/a&gt;, a framework for creating EPUB and PDF files from Markdown files. This entire thing is controlled by a single file checked into the Git repository.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;editions:
    epub:
        format:             mfgames-writing-epub
        theme:              ./lib/efferding
        outputDirectory:    .
        outputFilename:     sins-of-intent-{{edition.version}}.epub

    pdf:
        format:             mfgames-writing-weasyprint
        theme:              ./lib/efferding
        outputDirectory:    .
        outputFilename:     sins-of-intent-{{edition.version}}.pdf
        isbn:               978-1-940509-24-2

metadata:
    title:      Sins of Intent
    series:     Cletus Efferding
    author:     Randy Roeder
    language:   en

contents:
    - element: cover
      source: covers/v2/front.jpg
      linear: false
      exclude:
        editions: [pdf]
        toc: true
    - element: bastard
      source: frontmatter/bastard.html
      linear: false
      exclude:
        toc: true
    - element: title
      source: frontmatter/title.html
      linear: false
      exclude:
        toc: true
    - element: legal
      source: frontmatter/legal.md
      liquid: true
      linear: false
      exclude:
        toc: true
    - element: dedication
      source: frontmatter/dedication.md
      linear: false
      exclude:
        toc: true
    - element: toc
      linear: false
      exclude:
        editions: [pdf]
    - element: chapter
      number: 1
      directory: chapters
      source: /^chapter-\d+.md$/
      start: true
      page: 1
      pipeline: &amp;amp;pipelines
          - module: mfgames-writing-hyphen
            exceptions:
                # https://www.hyphenation24.com/word/driving/ says &amp;quot;driv-ing&amp;quot;
                - driving
                - drive
    - element: acknowledgement
      source: backmatter/acknowledgments.md
      pipeline: *pipelines
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This actually has turned out better than I expected. Yeah, I had trouble with using WeasyPrint for PDF generation, but it has almost all the features I needed to do right-side chapter openings, first page headers differently, and stitching everything into a single PDF with properly embedded fonts.&lt;/p&gt;
&lt;p&gt;The one thing I &lt;em&gt;can't&lt;/em&gt; do is create Smashword's Microsoft Word. I'm still trying to decide if it is worth it.&lt;/p&gt;
&lt;h1&gt;Website&lt;/h1&gt;
&lt;p&gt;I also release chapters every week. I used to use WordPress but it got cumbersome to add new chapters so I switched to a static site generator over the years. I started with DocPad, then Jekyll, and then extended Jekyll with Python and Perl programs to handle my requirements.&lt;/p&gt;
&lt;p&gt;Well&amp;hellip; I decided to write my own. This uses the same input files as the rest of my system (Markdown + YAML). It also lets me change a header to release the chapter and include it into the build.&lt;/p&gt;
&lt;p&gt;One of the complexities I had to figure out is the different repository for each novel. In the building process, I actually clone every project I'm publishing or have published, then use scripts to pull them into a single website before generating it. Jekyll couldn't handle it easily which is one reason I created my own.&lt;/p&gt;
&lt;p&gt;The tool for making the website is &lt;a href="https://gitlab.com/cobblestone-js/"&gt;CobblestoneJS&lt;/a&gt; but it has no documentation and I'm still fumbling through it. On the other hand, it handles the ten or so repositories needed to build &lt;a href="https://fedran.com/"&gt;fedran.com&lt;/a&gt; without my conlang, world data, and individual novels.&lt;/p&gt;
&lt;p&gt;As part of the weekly release, I've gotten the tasks down to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update a header in the YAML (or use the scheduler to do it once)&lt;/li&gt;
&lt;li&gt;Write a blog post about the chapter&lt;/li&gt;
&lt;li&gt;Copy the chapter and the post over to &lt;a href="https://ello.co/dmoonfire/"&gt;Ello&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Copy the chapter from fedran.com to Wattpad&lt;/li&gt;
&lt;li&gt;Copy the post over to Patreon&lt;/li&gt;
&lt;li&gt;Run the diaspora sync post&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It takes about 1-2 hours which is much shorter than the 4 is used to be.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Well, there it is, my current state of writing with Git. You have everything from writing the chapters, supplying metadata, how to store it, various tools for getting through the publication process, and even formatting it for the various vendors.&lt;/p&gt;
&lt;p&gt;I've gotten lost trying to automate and simplify a lot of this, but I think the current state is mostly usable by others and has been pretty solid for my own needs. I'm sure I'll improve and expand on it.&lt;/p&gt;
&lt;p&gt;If you have question or comments, please ask. I love talking about processes, looking for improvements, or explaining in more detail why I do these things.&lt;/p&gt;
&lt;p&gt;Thank you.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Overhead of Blogging</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2017/03/02/overhead-of-blogging/" />
    <updated>2017-03-02T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2017/03/02/overhead-of-blogging/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="broken-typewriter-press" scheme="https://d.moonfire.us/tags/" label="Broken Typewriter Press" />
    <category term="cobblestonejs" scheme="https://d.moonfire.us/tags/" label="CobblestoneJS" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">I got lost with a tangent where I try to create simple images for blog posts and ended up spending two days buildng a generic system.</summary>
    <content type="html">&lt;p&gt;After nearly burning myself out to finish 10k words before the end of the month, I decided to switch back over to working on my &lt;a href="https://broken.typewriter.press/"&gt;publishing business&lt;/a&gt; and getting ready to release my &lt;a href="https://fedran.com/sand-and-blood/"&gt;own books&lt;/a&gt; but also the next book I'm publishing.&lt;/p&gt;
&lt;p&gt;With some recent realizations, I found out my current incarnation of generating EPUB, MOBI, and PDF files was fragile. In specific, it required &lt;em&gt;my&lt;/em&gt; laptop to be set up properly. If I lost it&amp;mdash;not an unreasonable suggestion given that it has a hernia and a cracked shell&amp;mdash;then I would be significantly impacted.&lt;/p&gt;
&lt;p&gt;To fix that, I decided to rewrite the system (again) using TypeScript and NodeJS. This time, the packages are pushed up to shared servers which means others can contribute (yeah, right) but I also can rebuild the entire environment without having my specific machine.&lt;/p&gt;
&lt;p&gt;This also means that I can set up my &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt; installation to automatically build the EPUB, MOBI, and PDF files whenever I check files in. This also means the authors who have access to their own books can also make small corrections and see the results. In the end, it &lt;em&gt;should&lt;/em&gt; reduce the work it takes for me to publish which helps more than just myself.&lt;/p&gt;
&lt;p&gt;To simplify the logic, I'm building everything with HTML (EPUB's native format and MOBI's second language). However, there is not a good &lt;a href="https://www.sharelatex.com/learn/XeLaTeX"&gt;XeLaTeX&lt;/a&gt; conversion from HTML so I decided to try out &lt;a href="http://wkhtmltopdf.org/"&gt;wkhtmltopdf&lt;/a&gt; which I use for BTP's monthly statements. That worked out pretty well&amp;hellip; up to the point I found out I couldn't do inner and outer margins.&lt;/p&gt;
&lt;p&gt;Those are kind of important for books.&lt;/p&gt;
&lt;p&gt;When one thing creates a block, try a different one. After a while, I found a nice library called &lt;a href="http://weasyprint.org/"&gt;WeasyPrint&lt;/a&gt;. This handled inner and outer margins but&amp;hellip; it couldn't handle recto chapter pages (chapters opening on the right side) nor could it handle chapter-specific leading pages (no headers).&lt;/p&gt;
&lt;p&gt;So I have two ways of getting past this. I figured I could either hack the code by assembling the book and doing a bit of magic with the WeasyPrint code or do the &amp;ldquo;right&amp;rdquo; thing and teach that system how to handle recto and page numbers. I don't know which one is &amp;ldquo;easier&amp;rdquo; but I'm pretty sure there is a good chance I won't have time, but I'm willing to attempt it.&lt;/p&gt;
&lt;p&gt;I can always go back to XeLaTeX, I know how to convert that relatively quickly.&lt;/p&gt;
&lt;p&gt;Which&amp;hellip; leads me to my &lt;a href="https://xkcd.com/974/"&gt;974 Problem&lt;/a&gt;. I wanted to do a quick blog post about the stuff above. However, I didn't want to spent twenty minutes looking for an image to tag the post. My alternative was to create a &amp;ldquo;generic&amp;rdquo; image for posts that I didn't find an image. My novel posts will still probably have appropriate images.&lt;/p&gt;
&lt;p&gt;Instead of spending twenty minutes for an image, I spent two days writing a generic system including properly documented and tested library to integrate into my build system. Because ten hours verses twenty minutes is somehow better when I get lost in the forest.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Gulping down websites</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2016/11/04/website-changes/" />
    <updated>2016-11-04T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2016/11/04/website-changes/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="website" scheme="https://d.moonfire.us/tags/" label="Website" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">I've spent the last few days reworking the processes used to generate this website.</summary>
    <content type="html">&lt;p&gt;For the last few years, I've been using a Jekyll-based website. I started with a mostly stock setup, but it wasn't long before I was supplementing the results with Perl, Python, and a fairly complicated Makefile. This worked (and sucked out many hours out of my life) and I was pretty happy.&lt;/p&gt;
&lt;p&gt;As I've been posting repeatedly, the entire process has been getting slower and slower. The Jekyll version was taking ten to fifteen minute, which was frustrating when I'm trying to write a post (no preview).&lt;/p&gt;
&lt;p&gt;I also started doing serials. The weekly nature of posting could really use some scheduling. That way if I have a few hours to work ahead of time, I could write up the posts and get them queued up. Yes, I'm lazy but I also know that I've had more than a few postings minutes why of midnight.&lt;/p&gt;
&lt;p&gt;This year, I'm also planning on doing &lt;a href="http://www.frathwiki.com/Lexember"&gt;Lexember&lt;/a&gt;, a conlang-a-day challenge for December. This could &lt;em&gt;really&lt;/em&gt; use scheduled posts.&lt;/p&gt;
&lt;p&gt;Over the last week, I've created a Gulp-based system that creates the entire website. This will make it easier to work with Gitlab's CI service, which I trigger with a cron job. It also runs a lot faster.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;really&lt;/em&gt; hard part is to migrate the &lt;a href="https://fedran.com/"&gt;Fedran&lt;/a&gt; site over to this system because I have a &lt;em&gt;lot&lt;/em&gt; of logic, but that is an adventure for another year.&lt;/p&gt;
&lt;p&gt;Eventually, I'll actually write up the twenty Gulp plugins I've created to make this. Mainly, I just wanted to test the CI and scheduled posts.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Changes</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2015/06/22/changes/" />
    <updated>2015-06-22T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2015/06/22/changes/</id>
    <category term="work" scheme="https://d.moonfire.us/categories/" label="Work" />
    <category term="writing" scheme="https://d.moonfire.us/categories/" label="Writing" />
    <category term="accounting" scheme="https://d.moonfire.us/tags/" label="Accounting" />
    <category term="broken-typewriter-press" scheme="https://d.moonfire.us/tags/" label="Broken Typewriter Press" />
    <category term="discourse" scheme="https://d.moonfire.us/tags/" label="Discourse" />
    <category term="disqus" scheme="https://d.moonfire.us/tags/" label="Disqus" />
    <category term="feeds" scheme="https://d.moonfire.us/tags/" label="Feeds" />
    <category term="google-groups" scheme="https://d.moonfire.us/tags/" label="Google Groups" />
    <category term="mailing-lists" scheme="https://d.moonfire.us/tags/" label="Mailing Lists" />
    <category term="gitlab" scheme="https://d.moonfire.us/tags/" label="Gitlab" />
    <summary type="html">Life is about changes, both the little changes that happen from day to day and the big ones. In this case, it is the little changes of how I connect with readers online.</summary>
    <content type="html">&lt;p&gt;It's been a while since I've posted, I have to stop doing that. But, most of the time it is because I'm working on some project or dealing with life's little trials that make it hard to sit down and talk about them (or they are ones I choose not to share online).&lt;/p&gt;
&lt;p&gt;Trials have an interesting affect on me. I break out of my routine to deal with it and, when I go back, I realize that things I've done religiously are no longer things I want to do. A good example is that I used to play &lt;a href="https://www.kingdomofloathing.com/"&gt;Kingdom of Loathing&lt;/a&gt;. I love that game and played it every morning as part of my ritual. But, then I was flooded out of my apartment and spent three months without a laptop. When I came back, the joy had disappearing. I realized I was no longer playing the game but enjoying the puzzle of automating playing the game. So I dropped it.&lt;/p&gt;
&lt;p&gt;The latest trial popped out a few things that don't really work.&lt;/p&gt;
&lt;h1&gt;Penflip and Wattpad&lt;/h1&gt;
&lt;p&gt;I love the idea of &lt;a href="https://www.penflip.com/"&gt;Penflip&lt;/a&gt; and &lt;a href="http://www.wattpad.com/home"&gt;Wattpad&lt;/a&gt;. I've gotten a number of fans from posting frequently back before I wanted to be serious about writing.&lt;/p&gt;
&lt;p&gt;The problem is simple: pride. I want to produce the best piece of writing I can, but I simply don't have the skills to self-edit. Which means I need beta readers and editors before I feel I'm not throwing out garbage. At the moment, I don't have an army of fans who work for free, which means if I post my works-in-progress (WIP) on those sites, I'm posting &amp;ldquo;not my best quality.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This is a purely mental issue, I'm sure, but I don't want to be an author who puts out things with a &amp;ldquo;few mistakes.&amp;rdquo; I try to hold myself to a higher standard of not having mistakes or having very few (I still remember the &lt;em&gt;single&lt;/em&gt; typo I found in my copy of &lt;a href="http://www.amazon.com/gp/product/0671721046/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0671721046&amp;amp;linkCode=as2&amp;amp;tag=dmoo-20&amp;amp;linkId=VZZNKMEKBGGGZ7OF"&gt;Deeds of Paksenarrion&lt;/a&gt; in 1,024 pages).&lt;/p&gt;
&lt;p&gt;Before I had &lt;a href="https://sand-and-blood.fedran.com/"&gt;Sand and Blood&lt;/a&gt; re-edited, my dad read a copy. When he said &amp;ldquo;there weren't that many typos,&amp;rdquo; it actually bothered me a lot. And it was the other reason, besides the &lt;a href="http://creativityhacker.ca/2014/08/28/sand-and-blood-by-d-moonfire/"&gt;Immerse or Die review&lt;/a&gt;, that I decided to have it re-edited.&lt;/p&gt;
&lt;p&gt;The only way I could see posting on either of these sites is to complete them, have them edited, and then post online as a weekly or monthly serial until it completes. I'm considering doing it with &lt;em&gt;Sand and Blood&lt;/em&gt; if I ever make it &lt;a href="https://creativecommons.org/"&gt;Creative Commons&lt;/a&gt; licensed.&lt;/p&gt;
&lt;p&gt;Until then, I'll probably removing the pieces I have up already. I don't really have anyone reading them, so I don't mind. I'll keep the &lt;a href="https://journals.fedran.com/"&gt;Journals of Fedran&lt;/a&gt; issue #0 up until I get it edited, but issue #1 (which will be based on in-world religion) will remain offline until I can afford to get it edited.&lt;/p&gt;
&lt;h1&gt;Mailing Lists, Disqus, and Discourse&lt;/h1&gt;
&lt;p&gt;Another thing that is changing is my site comments. Previously, I used &lt;a href="https://disqus.com/"&gt;Disqus&lt;/a&gt; for the page comments. It is a useful service for smaller sites (which I'm very much one of them), but they also have some limitations such as being non-commerical for the free services, a constant push to buy their product, and linking all the sites together. Since they are free, I'm actually okay with that but that doesn't mean I have to stay with them.&lt;/p&gt;
&lt;p&gt;What pushed me over was getting DreamCompute from &lt;a href="http://www.dreamhost.com/r.cgi?80519"&gt;DreamHost&lt;/a&gt;, where I host my sites. It was mainly to have a &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt; instance but I had a second instance and I figured I'd go with the free alternative I've seen on a number of sites I liked, &lt;a href="http://www.discourse.org/"&gt;Discourse&lt;/a&gt;. It took me a little while to get it installed (had to learn &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; and a bit of &lt;a href="https://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt;) but I'm pretty happy with the result.&lt;/p&gt;
&lt;p&gt;If you are on my site, you can see it on the bottom of a number of pages. When you comment, it shows up at &lt;a href="https://discuss.moonfire.us/"&gt;discuss.moonfire.us&lt;/a&gt; but you can add new topics over on the discussion site.&lt;/p&gt;
&lt;p&gt;Having Discourse installed also meant that I could unify my mailing lists from Google Groups over to Discourse. That way, anyone interesting in commenting or reading or just talking about my world can post over there. And it handles email replies, which means it can also function as a full-blown mailing list for those who don't care for web forums.&lt;/p&gt;
&lt;p&gt;I'll be shutting down (i.e., deleting) the Google Groups probably by the end of the month or so. Or at least marking them as &amp;ldquo;read only.&amp;rdquo; If I have contests, they'll be posted over there (along with a blog post).&lt;/p&gt;
&lt;p&gt;The one drawback of Discourse is that it creates a topic as someone visits one of my pages. The steady stream of new posts has dwindled lately, but there is probably another 300-400 empty posts going to show up in the next few months. I never realized how much I wrote until I saw them popped up. It was also disheartening to see all my failed projects too.&lt;/p&gt;
&lt;h1&gt;My Time Has Value&lt;/h1&gt;
&lt;p&gt;The last one is a mental framework and less changes. I have a small publishing company called &lt;a href="https://brokentypewriterpress.com/"&gt;Broken Typewriter Press&lt;/a&gt; (BTP). It is what I use for doing ebook formatting, print typesetting, and all the little writing-related services that I offer (including commissioned writing, actually). I only have to pieces there, but my goal is to have a 1:10 ratio of my stuff to other author's.&lt;/p&gt;
&lt;p&gt;I have three books in the pipeline which will bring me to a 1:2 ratio (if you including my short story, &lt;span class="missing-link" data-path="/fiction/casting-call/"&gt;Casting Call&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;I'm treating it as a proper publishing company, which means I that if I'm publishing it, I don't charge the author and I recoup my costs via sales. Previously, I never included my time in making covers, typesetting, or formatting books I'm publishing. In effect, treating my personal time as having no value.&lt;/p&gt;
&lt;p&gt;I didn't have a problem when it was a one-off, those have invoices and I treat them as such.&lt;/p&gt;
&lt;p&gt;I can't really treat my time as zero anymore, it isn't fair to me or my family.&lt;/p&gt;
&lt;p&gt;This weekend, I went through and created some accounting sheets (avoiding doing the &amp;ldquo;proper&amp;rdquo; GnuCash until this becomes more of a business) to handle the profit/loss reports for individual authors. This time, I'm putting in items that I work on (in six minute intervals) so I can tell when I'm truly in the black verses when I've simply paid for the printing costs.&lt;/p&gt;
</content>
  </entry>
</feed>
