Private Ticket-Notizen mit Hugo Leaf Bundles


Bei meiner Arbeitsstelle werden Arbeitspakete mittels Tickets definiert und verteilt.

Wenn ich an diesen Tickets arbeite, notiere ich mir gerne den aktuellen Stand, welche Absprachen ich mit Kollegen getroffen habe, und woran ich gerade arbeite. Da diese Notizen nicht ins Ticketsystem gehören, habe ich mir eine eigene Lösung gebaut.

Aufbau


Ich möchte Informationen nur an ein Ticket anfügen und selten alte Informationen verändern. Daher organisiere ich die Tickets als Hugo leaf bundle. Das ermöglicht das einfache Einbinden anderer Dateien (sogenannte Ressourcen).

Jedes Ticket erhält einen Ordner (z. B. content/tickets/123456/). Eine index.md Datei enthält alle Metadaten und eine grobe Übersicht des Tickets, während alle Informationen, die sich ansammeln, in Ressourcendateien gespeichert werden. Diese sind bei mir nach Datum und Uhrzeit benannt (z. B. 2025-07-25-1243.md) und werden auf der Seite nach absteigendem Datum eingebunden, sodass neue Informationen immer einfach zu erreichen sind.

Um meinen Workflow zu vereinfachen, habe ich ein Skript geschrieben, das automatisch eine neue Datei im übergebenen Ticket erstellt, in die ich meine Notizen schreiben kann. Ist das Ticket neu, wird der komplette Ordner neu erstellt.

Beispiel


Feature #123456: Healthcheck Endpoint


Ticket

Health Check unter /healthy: Soll entweder Ok oder eine Fehlerbeschreibung zurückgeben.

12.07.2025, 09:17


Erste Implementierung, Probleme mit Komponente X: gibt immer healthy zurück. Möglich, dass der DB Error nicht gesetzt wird. Beim nächsten Meeting klären.

09.07.2025, 14:52


Mit: Franz Meier

Check soll auch für Komponente ABC implementiert werden.

01.07.2025, 10:23


Teambesprechung

Healthcheck für Monitoring geplant

Implementierung


Beispielhafte Ordnerstruktur

└ content/
   └ tickets/
      ├ 123456/
      │ ├ index.md
      │ ├ 2025-07-01-1023.md
      │ ├ 2025-07-09-1452.md
      │ └ 2025-07-12-0917.md
      └ 654321/
        ├ index.md
        ├ 2025-07-03-0958.md
        └ 2025-07-10-1402.md

new-info.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/bin/bash

# Check if parameter is provided
if [ $# -eq 0 ]; then
    echo "Error: Ticket number not provided"
    echo "Usage: $0 ticketNr"
    exit 1
fi

# Assign ticket number to variable
ticketNr=$1

BASE_DIR=$(dirname $(realpath "$0"))
TICKET_DIR="$BASE_DIR/content/tickets/${ticketNr}"

# Check if ticket directory exists, if not create it from template
if [ ! -d "$TICKET_DIR" ]; then
    # Copy template to new ticket directory
    mkdir "$TICKET_DIR"

    cat > ${TICKET_DIR}/index.md << EOL
---
title: "Neues Ticket"
ticketNr: ${ticketNr}
done: false
---
EOL

    echo "Directory created successfully."
fi

TIMESTAMP=$(date +"%Y-%m-%d-%H%M")
OUTPUT_FILE="$TICKET_DIR/$TIMESTAMP.md"

if [ -f "$OUTPUT_FILE" ]; then
    # Open existing file
    ${EDITOR:-vim} "$OUTPUT_FILE"
    echo "Edited existing file: $OUTPUT_FILE"
else
    # Create a temporary file for editing
    TEMP_FILE=$(mktemp)

    # Ensure temp file is removed on script exit, interrupt, etc.
    trap "rm -f $TEMP_FILE" EXIT INT TERM

    # Open editor (vim)
    ${EDITOR:-vim} "$TEMP_FILE"

    # Check if the file has content
    if [ -s "$TEMP_FILE" ]; then
        # Copy content to the final file
        cp "$TEMP_FILE" "$OUTPUT_FILE"

        echo "File saved as $OUTPUT_FILE"
    else
        echo "No content written, no file saved."
    fi
fi

exit 0

layouts/_default/tickets.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<h2>Aktuelle Tickets</h2>
{{ $tickets := where .Pages ".Params.done" false }}
{{ with $tickets }}
  <div>
    {{ range sort . ".Params.ticketNr" }}
      <p>
        <a href="{{ .Permalink }}">
          #{{ .Params.ticketNr }}: {{ .Title }}
        </a>
      </p>
    {{ end }}
  </div>
{{ else }}
  <p>Keine.</p>
{{ end }}

Sollen nur erledigte Tickets gezeigt werden, kann der Filter in Zeile zwei gedreht werden.

layouts/_default/single.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{{ range sort (.Resources.ByType "page") "Path" "desc" }}
  {{ $date := time  (substr .File.BaseFileName 0 10) }}
  {{ $hours := substr .File.BaseFileName 11 2 }}
  {{ $minutes := substr .File.BaseFileName 13 }}

  <div>
    <h3>
      {{ $date.Format "Mon, 02.01" }}{{ if ne (time.Now.Year) ($date.Year) }}{{ $date.Format ".2006" }}{{ end }}, {{ printf "%s:%s" $hours $minutes }}
    </h3>
    <hr>

    <div>
      {{ .Content }}
    </div>
  </div>

{{ end }}