I create a lot of projects. I think between Github and Gitlab, I have a few hundred now. Much if it is because I started pushing toward strictly being one story per repository (OSPR). This means I have a lot of common patterns that not only do I have to set up but also maintain as my skills and knowledge evolve. The problem comes when I figure out a new pattern, I have to update a couple hundred repositories if I want to keep them consistent. Needless to say, this is one drawback of a monorepo but there are a lot of advantages of OSPR.
A lot of my inspiration comes from Larry Wall's Three Virtues of a Great Programmer:
- Laziness: The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful and document what you wrote so you don't have to answer so many questions about it.
- Impatience: The anger you feel when the computer is being lazy. This makes you write programs that don't just react to your needs, but actually anticipate them. Or at least pretend to.
- Hubris: The quality that makes you write (and maintain) programs that other people won't want to say bad things about.
This means, instead of manually doing it, I want to find a nice automated way (virtue one) that I can script and have it run across everything at once (virtue two).
Previously, I had used Yeoman but I was wondering if I needed to break out of that to work on a “me-specific” CLI tool. That line of thought came down because so many of the tools I'm using all package their own custom CLIs. While I do enjoy writing a good CLI, I don't want to write one if I can't.
In the process of finding an alternative, I finally understood how to compose Yeoman generators together. That means I could create a generic project generator and then layer the writing one on top of it.
At the same time, I could migrate away from asdf and onto my preferred infrastructure du jour, Nix.
Side Note: Let me be honest, I'm constantly evolving my structures and they change as I learn new tools and my processes change with me. I won't be on Nix forever, but right now, Nix works out very nicely for what I want it to do.
This weekend I pulled something together and actually got a working version by tonight. This involves three projects:
- mfgames-writing: My publishing framework for Markdown and YAML files.
- generator-mfgames-nix-project: A Yeoman generator for creating a basic project layout.
- generator-mfgames-writing: A Yeoman generator for setting up a writing project.
I pulled out the basic project stuff from
generator-mfgames-writing and made it a dedicated generator while improving it. It still asks a bunch of questions, but mainly it does the following:
- Set up semantic-release to handle non-romantic releases. “Non-romantic” meaning automated and every time I push up to
- Set up Conventional Commits to drive the semantic release process. This is why my check-ins start with
fix:, or something other tag. That way, I can just focus on a given commit being a new feature, fixing something, or breaking everything.
- Set up commitlint to make sure the commits are properly handled for the semantic releasing.
- Set up Husky to make sure commitlint is automatically handled.
- Configure Prettier to make everything pretty and normalized. This mostly helps if someone ever contributes, but I like things being consistent and neat. While I disagree with Prettier on many things, it does a fantastic job.
- Set up a Nix flake to represent all the build tools needed to build the project.
- Set up direnv to automatically ‘enter’ the environment when you go into the directory.
- Write out the files needed to run Gitlab's CI/CD on push and generate all the files and automatically release.
- Set up EditorConfig for normalized formatting.
That's a lot of work and it was getting tedious as I migrated/created new projects over the last month or so as I figured out the pattern. I like it, though it is opinionated. Previously, I hated that word, but this is honestly how I work and I think it's a reasonable pattern for any writing or coding project.
Running it is pretty simple:
$ npm install -g generator-mfgames-nix-project yo $ mkdir name-of-project $ cd name-of-project $ yo mfgames-nix-project ... lots of prompting
Overall, I like the resulting project and I'm going to be testing it fairly heavily in the new few weeks.
Most of the intial work for
generator-mfgames-nix-project came from
generator-mfgames-writing, but I ended up also expanding that over the weekend to ask better questions about theme, author information, and the release process. It works the same as the project generator.
$ npm install -g generator-mfgames-writing yo $ mkdir name-of-project $ cd name-of-project $ yo mfgames-writing ... a different set of questions $ npm run build ... lots of noise $ ls *.epub *.pdf name-of-project-0.0.1.epub name-of-project-0.0.1.pdf
This one bypasses some questions that the project one does (build, test, and release questions) and adds some other ones (theme, configuration file format, title of the work), but otherwise works the same as the other. The end result is something you should be able to build and get the output immediately.
I honestly think that is really cool.
There were a bunch of versions with this, but I needed to tweak some processes because I found some bugs in these tools while writing the generators. Sadly, a “simple” fix of moving
rimraf from a developer dependency to a normal dependency required me to upgrade TypeScript to the last version and accept a wall of warnings because some of the linting tools don't like the latest version.