Standardisierte Prozesse sind toll

Wenn man viele kleine Programmierprojekte hat, sind Standardprozesse wirklich viel Wert. Ein kleines Beispiel mit Conventional Commits, Semantic Versioning und entsprechenden Werkzeugen.

Auf meinem Tolino mache ich mir immer wieder Anmerkungen, während ich Bücher lese. Die werden in einer Textdatei gespeichert. Um die zu parsen, habe ich mir von Google Gemini einfach ein Skript erzeugen lassen.

Früher hätte ich so etwas einfach in meinen Skripte-Ordner gepackt. Allerdings hätte ich dann keine Versionskontrolle gehabt. Und daher mache ich daraus ein eigenes Projekt und Repository. Das Setup dafür ist auch gar nicht mehr schwer, wenn man einfach Standardprozesse nimmt.

Für mich ist das Conventional Commits zum Verfassen der Git-Commit-Nachrichten. Dann nutze ich Semantic Versioning um zu entscheiden, welche die nächste Versionsnummer ist. Manchmal schreibe ich einen Changelog nach Keep-A-Changelog selbst, manchmal lasse ich den erzeugen. Ich nutze uv für das Python-Projekt und Commitizen für die Projekt-Logistik.

Und so habe ich gerade eine Änderung an meinem Skript gemacht:

tolino-note-extractor on  main [!] is 📦 v0.1.0 via 🐍 v3.14.2 
❯ git diff
diff --git a/src/tolino_note_extractor/__main__.py b/src/tolino_note_extractor/__main__.py
index 5d6497d..83a642c 100755
--- a/src/tolino_note_extractor/__main__.py
+++ b/src/tolino_note_extractor/__main__.py
@@ -23,8 +23,11 @@ def main() -> None:
     for author_title, notes in sorted_notes.items():
         print(f"# {author_title}")
         print()
-        print("\n\n---\n\n".join(map(dedent_lines, notes)))
-        print()
+        for note in notes:
+            print(dedent_lines(note))
+            print()
+            print("---")
+            print()


 def dedent_lines(s: str) -> str:

Da kann ich jetzt einfach ein Commit machen. Mein ca ist ein git commit --all --message '...'. Es ist ein neues Feature, also nutze ich feat: in der Nachricht:

tolino-note-extractor on  main [!] is 📦 v0.1.0 via 🐍 v3.14.2 
❯ ca feat: leave a trailing horizontal line
[main 116f34d] feat: leave a trailing horizontal line
 1 file changed, 5 insertions(+), 2 deletions(-)

Nun möchte ich diese neue Version veröffentlichen. Das ist normalerweise ziemlich viel kleinteilige Arbeit:

  1. Eine neue Versionnummer überlegen: Ist das nur ein Bugfix-Release oder gibt es ein neues Feature? Ist irgendwas kaputtgegangen, ist das sogar eine neue Major-Version? Oder wenn es Marketing-Versionen sind, welche nimmt man dann?
  2. Die neue Version in die pyproject.toml eintragen.
  3. Davon einen Commit machen.
  4. In Git einen Tag mit der Version anlegen.

Alles das kann ich mit nur einem Kommando machen, weil ich durch die Conventional Commits schon bei jedem Commit sage, wie groß der Sprung im Sinne von Semantic Versioning sein muss. Das Teil passt die pyproject.toml an, macht einen Commit und legt den Tag an:

tolino-note-extractor on  main is 📦 v0.1.0 via 🐍 v3.14.2 
❯ cz bump
bump: version 0.1.0 → 0.2.0
tag to create: 0.2.0
increment detected: MINOR

[main aa1b8b2] bump: version 0.1.0 → 0.2.0
 3 files changed, 8 insertions(+), 2 deletions(-)

Done!

Dann kann ich das ganze direkt mit uv bauen:

tolino-note-extractor on  main is 📦 v0.2.0 via 🐍 v3.14.2 
❯ uv build
Building source distribution...
Building wheel from source distribution...
Successfully built dist/tolino_note_extractor-0.2.0.tar.gz
Successfully built dist/tolino_note_extractor-0.2.0-py3-none-any.whl

Weil mein Projekt ja einfach nur ein Python-Paket ist, kann ich das dann auch sofort damit installieren:

tolino-note-extractor on  main is 📦 v0.2.0 via 🐍 v3.14.2 
❯ uv tool install dist/tolino_note_extractor-0.2.0-py3-none-any.whl
Resolved 1 package in 1ms
Prepared 1 package in 3ms
Uninstalled 1 package in 0.73ms
Installed 1 package in 2ms
 - tolino-note-extractor==0.1.0 (from file:///home/mu/Projekte/tolino-note-extractor/dist/tolino_note_extractor-0.1.0-py3-none-any.whl)
 + tolino-note-extractor==0.2.0 (from file:///home/mu/Projekte/tolino-note-extractor/dist/tolino_note_extractor-0.2.0-py3-none-any.whl)
Installed 1 executable: extract-tolino-notes

Und schon kann ich es nutzen. Das sind zwar mehr Schritte als bei einem Skript im Skripte-Ordner, dafür ist das Skript dann auch als eigenes Repository online verfügbar. Zudem habe ich auch eine Liste der Änderungen, was ich ganz angenehm finde:

tolino-note-extractor on  main is 📦 v0.2.0 via 🐍 v3.14.2 
❯ git log --oneline
aa1b8b2 (HEAD -> main, tag: 0.2.0) bump: version 0.1.0 → 0.2.0
116f34d feat: leave a trailing horizontal line
d4c86d5 (tag: 0.1.0) bump: version 0.0.0 → 0.1.0
469f3c4 build: do not use v prefix
0c4a3e8 build: set version to no release yet
d6d8161 build: add commitizen
0eaa7bb feat: dedent lines
417d6ba feat: print more like Markdown
9922a58 feat: also extract type
ee6ff3c build: rename script
cfb665e build: expose CLI entrypoint
be15db6 feat: print out notes in CLI
316efdc feat: fix regular expression with NBSP
f640ee6 build: start with project skeleton
953fdc7 Init

Zudem kann ich auf bestimmte Versionen zugreifen:

tolino-note-extractor on  main is 📦 v0.2.0 via 🐍 v3.14.2 
❯ git tag
0.1.0
0.2.0

Und einen Changelog gibt es auch noch:

## 0.2.0 (2026-02-28)

### Feat

- leave a trailing horizontal line

## 0.1.0 (2026-02-28)

### Feat

- dedent lines
- print more like Markdown
- also extract type
- print out notes in CLI
- fix regular expression with NBSP

Der Changelog ist nicht ganz so gut wie ein handgeschriebener. Aber für so ein Skript reicht mir das. Und es erzeugt keine zusätzliche Arbeit. Und das ist ein Kosten-Nutzen-Verhältnis, das mich dann sehr anspricht. Ein Hoch auf standardisierte Prozesse!