Compare commits
14 commits
Author | SHA1 | Date | |
---|---|---|---|
D. Moonfire | acca1e3ed4 | ||
400101da34 | |||
D. Moonfire | edb2f36b57 | ||
D. Moonfire | 872628fe05 | ||
D. Moonfire | a08ba9ad4c | ||
D. Moonfire | 875a0daeca | ||
D. Moonfire | b165698a97 | ||
D. Moonfire | 8723fe4842 | ||
dd321fea14 | |||
D. Moonfire | 9b15f8102f | ||
D. Moonfire | 137784dda6 | ||
b8f9c0daca | |||
D. Moonfire | b306147176 | ||
D. Moonfire | d1ed71eff1 |
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
releases.yml
|
||||
|
||||
*~
|
||||
*.epub
|
||||
*.mobi
|
||||
|
|
47
.woodpecker.yml
Normal file
47
.woodpecker.yml
Normal file
|
@ -0,0 +1,47 @@
|
|||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
tags: true
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
|
||||
commands:
|
||||
- nix develop --command scripts/build.sh
|
||||
when:
|
||||
event: [push, tag, manual]
|
||||
tag: v*
|
||||
branch: main
|
||||
|
||||
test:
|
||||
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
|
||||
commands:
|
||||
- nix develop --command scripts/test.sh
|
||||
when:
|
||||
event: [push, manual]
|
||||
branch: main
|
||||
|
||||
release-main:
|
||||
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
|
||||
commands:
|
||||
- nix develop --command scripts/release.sh
|
||||
secrets:
|
||||
- gitea_token
|
||||
- git_credentials
|
||||
when:
|
||||
event: [push, manual]
|
||||
branch: main
|
||||
|
||||
release-gitea:
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
base_url: https://src.mfgames.com
|
||||
files:
|
||||
- "*.pdf"
|
||||
- "*.epub"
|
||||
api_key:
|
||||
from_secret: gitea_token
|
||||
when:
|
||||
event: tag
|
||||
tag: v*
|
|
@ -1,26 +0,0 @@
|
|||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
tags: true
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
|
||||
commands:
|
||||
- nix develop --command scripts/build.sh
|
||||
- nix develop --command scripts/test.sh
|
||||
when:
|
||||
event: [push, pull_request]
|
||||
release:
|
||||
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
|
||||
commands:
|
||||
- export DRONE="true" # Required to convince `env-ci` that it is a known CI
|
||||
- git branch $DRONE_BRANCH origin/$DRONE_BRANCH # semantic-release needs this locally
|
||||
- nix develop --command scripts/release.sh
|
||||
secrets:
|
||||
- gitea_token
|
||||
- git_credentials
|
||||
when:
|
||||
event: [push]
|
||||
branch: main
|
|
@ -1,25 +0,0 @@
|
|||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
tags: true
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest
|
||||
commands:
|
||||
- nix develop --command scripts/build.sh
|
||||
when:
|
||||
event: [tag]
|
||||
tag: v*
|
||||
gitea:
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
base_url: https://src.mfgames.com
|
||||
files: exit-planning*.*
|
||||
secrets:
|
||||
- source: gitea_token
|
||||
target: plugin_api_key
|
||||
when:
|
||||
event: [tag]
|
||||
tag: v*
|
4
dmoonfire.json
Normal file
4
dmoonfire.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"categories": ["Development"],
|
||||
"summary": "Methods for working with projects that use different frameworks (such as C# and TypeScript) including how to handle the different build systems and processes."
|
||||
}
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "project-layout",
|
||||
"version": "3.0.1",
|
||||
"version": "3.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "project-layout",
|
||||
"version": "3.0.1",
|
||||
"version": "3.1.0",
|
||||
"dependencies": {
|
||||
"@mfgames-writing/clean-theme": "^4.0.2",
|
||||
"@mfgames-writing/contracts": "^4.2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "project-layout",
|
||||
"description": "A method for organizing multiple polygot source projects.",
|
||||
"version": "3.0.1",
|
||||
"version": "3.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:pdf": "mfgames-writing-format build pdf",
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
# !/usr/bin/env bash
|
||||
|
||||
#mfgames-project:setup@v0.0.0
|
||||
log() { echo "🚧 $(basename $0): $@"; }
|
||||
cd $(dirname $(dirname $0))
|
||||
#mfgames-project:setup
|
||||
|
||||
log "cleaning old files"
|
||||
rm -f *.epub *.pdf
|
||||
|
||||
log "installing NPM"
|
||||
npm install --ci
|
||||
|
||||
log "running build"
|
||||
npm run build
|
||||
|
|
66
scripts/mfgames-project-script-builder.sh
Executable file
66
scripts/mfgames-project-script-builder.sh
Executable file
|
@ -0,0 +1,66 @@
|
|||
# !/usr/bin/env bash
|
||||
|
||||
## mfgames-project:v0.0.0
|
||||
|
||||
## mfgames-project
|
||||
|
||||
# Variables
|
||||
version=0.0.0
|
||||
|
||||
# Make sure we have the proper parameters.
|
||||
usage() {
|
||||
echo "USAGE $0 script.sh [script2.sh]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "x$1" = "x" ]
|
||||
then
|
||||
usage
|
||||
fi
|
||||
|
||||
# Go through the script and look for each one.
|
||||
for script in "$@"
|
||||
do
|
||||
# Write out the file.
|
||||
echo '# !/usr/bin/env bash' > .mfgames-project.tmp
|
||||
|
||||
if [ -f $script ]
|
||||
then
|
||||
cat $script \
|
||||
| sed -n '/usr.bin.env bash/!p' \
|
||||
| sed '/^#mfgames-project:setup@/q' \
|
||||
| sed -n '/mfgames-project:setup/!p' \
|
||||
>> .mfgames-project.tmp
|
||||
else
|
||||
echo >> .mfgames-project.tmp
|
||||
fi
|
||||
|
||||
echo "#mfgames-project:setup@v$version" >> .mfgames-project.tmp
|
||||
|
||||
if [ -f $script ] && grep 'log() { echo' $script > /dev/null
|
||||
then
|
||||
grep 'log() { echo' $script >> .mfgames-project.tmp
|
||||
else
|
||||
case $script in
|
||||
build.sh) unicode="🚧" ;;
|
||||
release.sh) unicode="🚢" ;;
|
||||
setup.sh) unicode="🌱" ;;
|
||||
test.sh) unicode="🧪" ;;
|
||||
*) unicode=$(unipicker) ;;
|
||||
esac
|
||||
|
||||
echo "log() { echo \"$unicode \$(basename \$0): \$@\"; }" >> .mfgames-project.tmp
|
||||
fi
|
||||
|
||||
echo "cd \$(dirname \$(dirname \$0))" >> .mfgames-project.tmp
|
||||
echo "#mfgames-project:setup" >> .mfgames-project.tmp
|
||||
|
||||
if [ -f $script ]
|
||||
then
|
||||
sed '1,/^#mfgames-project:setup$/d' < $script >> .mfgames-project.tmp
|
||||
fi
|
||||
|
||||
# Finish up and make the script executable.
|
||||
mv .mfgames-project.tmp $script
|
||||
chmod a+x $script
|
||||
done
|
|
@ -1,4 +1,15 @@
|
|||
cd $(dirname $0)/..
|
||||
# !/usr/bin/env bash
|
||||
|
||||
#mfgames-project:setup@v0.0.0
|
||||
log() { echo "🚢 $(basename $0): $@"; }
|
||||
cd $(dirname $(dirname $0))
|
||||
#mfgames-project:setup
|
||||
|
||||
log "cleaning old old version"
|
||||
rm -f exit-planning*
|
||||
|
||||
log "installing NPM"
|
||||
npm install --ci
|
||||
|
||||
log "running release"
|
||||
npx semantic-release
|
||||
|
|
|
@ -1,2 +1,12 @@
|
|||
# !/usr/bin/env bash
|
||||
|
||||
#mfgames-project:setup@v0.0.0
|
||||
log() { echo "🧪 $(basename $0): $@"; }
|
||||
cd $(dirname $(dirname $0))
|
||||
#mfgames-project:setup
|
||||
|
||||
log "installing NPM"
|
||||
npm install --ci
|
||||
|
||||
log "verifying commits"
|
||||
npx commitlint-gitlab-ci -x @commitlint/config-conventional
|
||||
|
|
89
src/index.md
89
src/index.md
|
@ -1,41 +1,16 @@
|
|||
---
|
||||
title: Project Layout
|
||||
date: 2022-04-01
|
||||
version: 3.0.0
|
||||
categories:
|
||||
- Development
|
||||
tags:
|
||||
- "C#"
|
||||
- Typescript
|
||||
- Rust
|
||||
- asdf
|
||||
- Nix
|
||||
- Semantic Releases
|
||||
- Conventional Commits
|
||||
- Nitride
|
||||
- Webpack
|
||||
- Cake
|
||||
- Lefthook
|
||||
- Husky
|
||||
- Linux
|
||||
- powershell
|
||||
- Windows
|
||||
- GitLab
|
||||
summary: >
|
||||
Organizing project structures when being a polyglot coder.
|
||||
---
|
||||
# Project Layout
|
||||
|
||||
I'm a polyglot programmer. I work in a variety of languages but mostly in [C#](/tags/c-sharp/), [Typescript](/tags/typescript/), and [Rust](/tags/rust/). Every few years, I try a new language to see if I can pick up new ideas or if one "fits" my current mental state better. This is also why I've done a lot dozens of other languages; I would say I know over thirty languages but I'm only a "master" in a handful.
|
||||
|
||||
I also flit from project to project. I have my [writing](/categories/writing/) and games. I have little one-off programs and ones that I hope will become a major thing. But, like everything else in my life, I'm "gloriously unfocused" on my tasks which means I have to minimize the speed that I get into a project.
|
||||
I also flit from project to project. I have my [writing](/categories/writing/) and games. I have little one-off programs and ones that I hope will become a major thing. But, like everything else in my life, I'm "gloriously unfocused" on my tasks which means I have to minimize the speed that I get into a project before the muse escapes me.
|
||||
|
||||
# Tools Selection
|
||||
## Tools Selection
|
||||
|
||||
One of the earliest approaches I had to try getting a proper environment at the per-project level was [asdf](/tags/asdf). It worked out fairly well for a few years, but then I noticed that my various novels and stories were getting fragile. There were limitations that `asdf` couldn't handle easily which meant I needed something more reliable. That led me into [Nix](/tags/nix/) which is my current setup because entering the directory sets up that project's settings while still giving me the reproducibility I need for my novels.
|
||||
|
||||
This means that most of my projects now have a `./flake.nix` and a `./flake.lock` in the root level.
|
||||
|
||||
# Building, Releasing, and Actions
|
||||
## Building, Releasing, and Actions
|
||||
|
||||
Because I've fallen in love with [Semantic Releases](/tags/semantic-release/) and [Conventional Commits](/tags/conventional-commits/), a lot of my processes are built around those. In earlier projects, that usually meant that almost every project _also_ included Node in some form so I could use [semantic-release](https://github.com/semantic-release/semantic-release). That also meant I could use `package.json` to handle versioning.
|
||||
|
||||
|
@ -43,6 +18,8 @@ Though, recent thoughts have suggested that I need to break that "one tool fits
|
|||
|
||||
This is where being a polyglot and using different tools comes into play. I have a website that does C#, Typescript, and SASS at the same time. Which one is the "root", which command drives everything? What about a Rust project? Or something else?
|
||||
|
||||
### Shell Scripts
|
||||
|
||||
That has kind of led me to my current approach. Instead of always packaging Node in my projects, I really should have a standard location to handle the various actions/targets that apply to any project. Right now, that seems to be shell scripts.
|
||||
|
||||
With shell scripts, I just have to know that `./scripts/build.sh` will do whatever is needed to build the target. Same with `./scripts/test.sh` and `./scripts/release.sh`. A Rust project may call Cargo, a .NET project will call `dotnet`, and polyglot will call any and all needed to build it.
|
||||
|
@ -52,3 +29,57 @@ This will give me room to experiment. If I decide I want to play with [Cake](/ta
|
|||
I also went with `.sh` suffixes on the files because while I mostly code in [Linux](/tags/linux/), I also want to support [Powershell](/tags/powershell/) and [Windows](/tags/windows/). That way, it is also clear that `build.sh` and `build.ps1` probably result in the same end-result, but specific for that language. (I know Powershell runs on Linux too.)
|
||||
|
||||
Obviously, some documentation would be required, but that could be a `README.md` file in that directory. That will look nice in [GitLab](/tags/gitlab/) and give documentation.
|
||||
|
||||
### Paths
|
||||
|
||||
Fortunately, I use [direnv](https://direnv.net/) and [nix-direnv](https://github.com/nix-community/nix-direnv) frequently in my development. This loads the `flake.nix` file as soon as I enter the directory and sets up the tools I need. It also gives me a chance to modify the `PATH` variable but only for that directory which means I can add the `./scripts` folder into the path and have it available anywhere inside the project.
|
||||
|
||||
```shell
|
||||
export PATH=$PWD/scripts:$PATH
|
||||
use flake || use nix
|
||||
```
|
||||
|
||||
When working with packaging systems such as Node that also include scripts, I also add those into the path. In both cases, `$PWD` is always the directory with the `.envrc` file, even if I change directly into somewhere deeper into the proejct tree; using `$PWD/scripts` means that the `build.sh` command is available anywhere.
|
||||
|
||||
```shell
|
||||
export PATH=$PWD/scripts:$PWD/node-modules/.bin:$PATH
|
||||
use flake || use nix
|
||||
```
|
||||
|
||||
### Boilerplates
|
||||
|
||||
Over the half year or so that I've been using this, I found that I was introducing a few new patterns into my scripts. Mostly these were to support CI/CD environments but also because I like feedback that scripts are doing something.
|
||||
|
||||
The most notable aspects were to almost always move into the root directory of the project.
|
||||
|
||||
```shell
|
||||
#! /usr/bin/env bash
|
||||
cd $(dirname $(dirname $0))
|
||||
```
|
||||
|
||||
In the above case, `$0` is the name of the script. The first `dirname` gets me into the `./scripts` folder, the second gets me into the root. That means that even if I call this script from deep inside the project, the paths are always relative to the project root.
|
||||
|
||||
The other is to set up logging so I have something to see what is going on. This is useful for the CI process, but also just so I know something is working properly. I ended up using a consistent start to the scripts to help me identify where the build process was.
|
||||
|
||||
```shell
|
||||
log() { echo "️🧪 $(basename $0): $@"; }
|
||||
log "running tests/gregorian-tests.scm"
|
||||
some testing code
|
||||
```
|
||||
|
||||
When run, it looks like this:
|
||||
|
||||
```shell
|
||||
$ test.sh
|
||||
🧪 test.sh: running tests/gregorian-tests.scm
|
||||
......................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 38 tests in 0.001s
|
||||
|
||||
OK
|
||||
$
|
||||
```
|
||||
|
||||
Each script usually has their only Unicode character, which also gives the logs a nice colorful appearance and really makes it easier to see where things are going. I ended up using a Bash function for this because it simplifed the calls into a simple `log message` and made it easier to function.
|
||||
|
||||
Sadly, Bash doesn't have a good packaging story, so I just copy/paste this into the top of every script along with the `#! /usr/bin/env bash` shebang. Overall, it seems to work and I've been pretty happy with it since.
|
||||
|
|
Loading…
Reference in a new issue