C1: migrate cv + docs from minikube to indri-native #342
16 changed files with 415 additions and 136 deletions
|
|
@ -178,10 +178,11 @@ jobs:
|
||||||
|
|
||||||
echo "## Documentation"
|
echo "## Documentation"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Download \`$TARBALL\` and configure the quartz container with:"
|
echo "Download \`$TARBALL\` directly, or bump \`docs_version\`"
|
||||||
|
echo "in \`ansible/roles/docs/defaults/main.yml\` and run:"
|
||||||
echo ""
|
echo ""
|
||||||
echo "\`\`\`"
|
echo "\`\`\`"
|
||||||
echo "DOCS_RELEASE_URL=https://forge.eblu.me/eblume/blumeops/releases/download/$VERSION/$TARBALL"
|
echo "mise run provision-indri -- --tags docs"
|
||||||
echo "\`\`\`"
|
echo "\`\`\`"
|
||||||
} > /tmp/release_body.txt
|
} > /tmp/release_body.txt
|
||||||
|
|
||||||
|
|
@ -223,18 +224,16 @@ jobs:
|
||||||
echo ""
|
echo ""
|
||||||
echo "Release created successfully!"
|
echo "Release created successfully!"
|
||||||
|
|
||||||
- name: Update docs deployment
|
- name: Bump docs_version in ansible role
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
TARBALL="docs-${VERSION}.tar.gz"
|
DEFAULTS_FILE="ansible/roles/docs/defaults/main.yml"
|
||||||
DEPLOYMENT_FILE="argocd/manifests/docs/deployment.yaml"
|
|
||||||
RELEASE_URL="https://forge.eblu.me/eblume/blumeops/releases/download/${VERSION}/${TARBALL}"
|
|
||||||
|
|
||||||
echo "Updating $DEPLOYMENT_FILE with new release URL..."
|
echo "Bumping docs_version in $DEFAULTS_FILE to ${VERSION}..."
|
||||||
yq -i "(.spec.template.spec.containers[0].env[] | select(.name == \"DOCS_RELEASE_URL\")).value = \"${RELEASE_URL}\"" "$DEPLOYMENT_FILE"
|
yq -i ".docs_version = \"${VERSION}\"" "$DEFAULTS_FILE"
|
||||||
|
|
||||||
echo "Updated deployment:"
|
echo "Updated defaults:"
|
||||||
grep -A1 "DOCS_RELEASE_URL" "$DEPLOYMENT_FILE"
|
grep -E "^docs_version:" "$DEFAULTS_FILE"
|
||||||
|
|
||||||
- name: Commit release changes
|
- name: Commit release changes
|
||||||
env:
|
env:
|
||||||
|
|
@ -248,7 +247,7 @@ jobs:
|
||||||
git config user.email "actions@forge.ops.eblu.me"
|
git config user.email "actions@forge.ops.eblu.me"
|
||||||
|
|
||||||
# Stage deployment changes
|
# Stage deployment changes
|
||||||
git add argocd/manifests/docs/deployment.yaml
|
git add ansible/roles/docs/defaults/main.yml
|
||||||
|
|
||||||
# Stage changelog changes if updated
|
# Stage changelog changes if updated
|
||||||
if [ "$CHANGELOG_UPDATED" = "true" ]; then
|
if [ "$CHANGELOG_UPDATED" = "true" ]; then
|
||||||
|
|
@ -270,34 +269,6 @@ jobs:
|
||||||
echo "Changes committed and pushed"
|
echo "Changes committed and pushed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Deploy docs
|
|
||||||
env:
|
|
||||||
ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "Syncing docs app via ArgoCD..."
|
|
||||||
|
|
||||||
# Sync docs app (uses ARGOCD_AUTH_TOKEN env var for auth)
|
|
||||||
argocd app sync docs \
|
|
||||||
--server argocd.ops.eblu.me \
|
|
||||||
--grpc-web \
|
|
||||||
--prune
|
|
||||||
|
|
||||||
# Wait for sync to complete
|
|
||||||
argocd app wait docs \
|
|
||||||
--server argocd.ops.eblu.me \
|
|
||||||
--grpc-web \
|
|
||||||
--timeout 120
|
|
||||||
|
|
||||||
echo "Docs app synced successfully!"
|
|
||||||
|
|
||||||
- name: Purge Fly.io proxy cache
|
|
||||||
env:
|
|
||||||
FLY_API_TOKEN: ${{ secrets.FLY_DEPLOY_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "Purging nginx cache on Fly.io proxy..."
|
|
||||||
fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'"
|
|
||||||
echo "Cache purged"
|
|
||||||
|
|
||||||
- name: Summary
|
- name: Summary
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
|
@ -309,5 +280,12 @@ jobs:
|
||||||
echo "Release URL:"
|
echo "Release URL:"
|
||||||
echo " https://forge.eblu.me/eblume/blumeops/releases/tag/$VERSION"
|
echo " https://forge.eblu.me/eblume/blumeops/releases/tag/$VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Asset URL (for DOCS_RELEASE_URL ConfigMap):"
|
echo "Asset URL:"
|
||||||
echo " https://forge.eblu.me/eblume/blumeops/releases/download/$VERSION/$TARBALL"
|
echo " https://forge.eblu.me/eblume/blumeops/releases/download/$VERSION/$TARBALL"
|
||||||
|
echo ""
|
||||||
|
echo "To deploy on indri, run from gilbert:"
|
||||||
|
echo " mise run provision-indri -- --tags docs"
|
||||||
|
echo ""
|
||||||
|
echo "Then purge the Fly.io proxy cache:"
|
||||||
|
echo " fly ssh console -a blumeops-proxy -C \\"
|
||||||
|
echo " \"sh -c 'rm -rf /tmp/cache && nginx -s reload'\""
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
# CV Deploy Workflow
|
# CV Deploy Workflow
|
||||||
#
|
#
|
||||||
# Updates the CV deployment to a specific package version, commits
|
# Bumps cv_version in ansible/roles/cv/defaults/main.yml and pushes the change.
|
||||||
# the change, and syncs via ArgoCD.
|
# Deployment to indri is manual (runner has no SSH access to indri):
|
||||||
|
# mise run provision-indri -- --tags cv
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# 1. Release a new CV package from the cv repo first
|
# 1. Release a new CV package from the cv repo first
|
||||||
# 2. Go to Actions > Deploy CV > Run workflow
|
# 2. Go to Actions > Deploy CV > Run workflow
|
||||||
# 3. Enter the version to deploy, or leave as "latest"
|
# 3. Enter the version to deploy, or leave as "latest"
|
||||||
|
# 4. Run the command above on gilbert to apply
|
||||||
|
|
||||||
name: Deploy CV
|
name: Deploy CV
|
||||||
|
|
||||||
|
|
@ -60,18 +62,16 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
- name: Update CV deployment
|
- name: Bump cv_version in ansible role
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
TARBALL="cv-${VERSION}.tar.gz"
|
DEFAULTS_FILE="ansible/roles/cv/defaults/main.yml"
|
||||||
DEPLOYMENT_FILE="argocd/manifests/cv/deployment.yaml"
|
|
||||||
RELEASE_URL="https://forge.eblu.me/api/packages/eblume/generic/cv/${VERSION}/${TARBALL}"
|
|
||||||
|
|
||||||
echo "Updating $DEPLOYMENT_FILE with CV_RELEASE_URL..."
|
echo "Bumping cv_version in $DEFAULTS_FILE to ${VERSION}..."
|
||||||
yq -i "(.spec.template.spec.containers[0].env[] | select(.name == \"CV_RELEASE_URL\")).value = \"${RELEASE_URL}\"" "$DEPLOYMENT_FILE"
|
yq -i ".cv_version = \"${VERSION}\"" "$DEFAULTS_FILE"
|
||||||
|
|
||||||
echo "Updated deployment:"
|
echo "Updated defaults:"
|
||||||
grep -A1 "CV_RELEASE_URL" "$DEPLOYMENT_FILE"
|
grep -E "^cv_version:" "$DEFAULTS_FILE"
|
||||||
|
|
||||||
- name: Commit release changes
|
- name: Commit release changes
|
||||||
env:
|
env:
|
||||||
|
|
@ -82,7 +82,7 @@ jobs:
|
||||||
git config user.name "Forgejo Actions"
|
git config user.name "Forgejo Actions"
|
||||||
git config user.email "actions@forge.ops.eblu.me"
|
git config user.email "actions@forge.ops.eblu.me"
|
||||||
|
|
||||||
git add argocd/manifests/cv/deployment.yaml
|
git add ansible/roles/cv/defaults/main.yml
|
||||||
|
|
||||||
if git diff --cached --quiet; then
|
if git diff --cached --quiet; then
|
||||||
echo "No changes to commit (already at $VERSION)"
|
echo "No changes to commit (already at $VERSION)"
|
||||||
|
|
@ -94,38 +94,16 @@ jobs:
|
||||||
echo "Changes committed and pushed"
|
echo "Changes committed and pushed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Deploy CV
|
|
||||||
env:
|
|
||||||
ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "Syncing CV app via ArgoCD..."
|
|
||||||
|
|
||||||
argocd app sync cv \
|
|
||||||
--server argocd.ops.eblu.me \
|
|
||||||
--grpc-web \
|
|
||||||
--prune
|
|
||||||
|
|
||||||
argocd app wait cv \
|
|
||||||
--server argocd.ops.eblu.me \
|
|
||||||
--grpc-web \
|
|
||||||
--timeout 120
|
|
||||||
|
|
||||||
echo "CV app synced successfully!"
|
|
||||||
|
|
||||||
- name: Purge Fly.io proxy cache
|
|
||||||
env:
|
|
||||||
FLY_API_TOKEN: ${{ secrets.FLY_DEPLOY_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "Purging nginx cache on Fly.io proxy..."
|
|
||||||
fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'"
|
|
||||||
echo "Cache purged"
|
|
||||||
|
|
||||||
- name: Summary
|
- name: Summary
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
echo "================================================"
|
echo "================================================"
|
||||||
echo "CV Deployed: $VERSION"
|
echo "CV version bumped: $VERSION"
|
||||||
echo "================================================"
|
echo "================================================"
|
||||||
echo ""
|
echo ""
|
||||||
echo "CV should now be live at:"
|
echo "To deploy on indri, run from gilbert:"
|
||||||
echo " https://cv.ops.eblu.me/"
|
echo " mise run provision-indri -- --tags cv"
|
||||||
|
echo ""
|
||||||
|
echo "Then purge the Fly.io proxy cache:"
|
||||||
|
echo " fly ssh console -a blumeops-proxy -C \\"
|
||||||
|
echo " \"sh -c 'rm -rf /tmp/cache && nginx -s reload'\""
|
||||||
|
|
|
||||||
|
|
@ -256,5 +256,9 @@
|
||||||
tags: jellyfin_metrics
|
tags: jellyfin_metrics
|
||||||
- role: forgejo_metrics
|
- role: forgejo_metrics
|
||||||
tags: forgejo_metrics
|
tags: forgejo_metrics
|
||||||
|
- role: cv
|
||||||
|
tags: cv
|
||||||
|
- role: docs
|
||||||
|
tags: docs
|
||||||
- role: caddy
|
- role: caddy
|
||||||
tags: caddy
|
tags: caddy
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,16 @@ caddy_services:
|
||||||
backend: "https://go.tail8d86e.ts.net"
|
backend: "https://go.tail8d86e.ts.net"
|
||||||
- name: docs
|
- name: docs
|
||||||
host: "docs.{{ caddy_domain }}"
|
host: "docs.{{ caddy_domain }}"
|
||||||
backend: "https://docs.tail8d86e.ts.net"
|
kind: static
|
||||||
|
root: "{{ docs_content_dir }}"
|
||||||
|
try_html: true # Quartz: path → path/ → path.html → 404.html
|
||||||
- name: cv
|
- name: cv
|
||||||
host: "cv.{{ caddy_domain }}"
|
host: "cv.{{ caddy_domain }}"
|
||||||
backend: "https://cv.tail8d86e.ts.net"
|
kind: static
|
||||||
|
root: "{{ cv_content_dir }}"
|
||||||
|
download_paths:
|
||||||
|
- path: /resume.pdf
|
||||||
|
filename: erich-blume-resume.pdf
|
||||||
- name: nvr
|
- name: nvr
|
||||||
host: "nvr.{{ caddy_domain }}"
|
host: "nvr.{{ caddy_domain }}"
|
||||||
backend: "https://nvr.tail8d86e.ts.net"
|
backend: "https://nvr.tail8d86e.ts.net"
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,25 @@
|
||||||
{% for service in caddy_services %}
|
{% for service in caddy_services %}
|
||||||
@{{ service.name }} host {{ service.host }}
|
@{{ service.name }} host {{ service.host }}
|
||||||
handle @{{ service.name }} {
|
handle @{{ service.name }} {
|
||||||
|
{% if service.kind | default('proxy') == 'static' %}
|
||||||
|
root * {{ service.root }}
|
||||||
|
encode gzip
|
||||||
|
# Long-cache fingerprinted assets; everything else stays default.
|
||||||
|
@{{ service.name }}_assets path_regexp \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$
|
||||||
|
header @{{ service.name }}_assets Cache-Control "public, max-age=31536000, immutable"
|
||||||
|
{% for dl in service.download_paths | default([]) %}
|
||||||
|
@{{ service.name }}_dl{{ loop.index }} path {{ dl.path }}
|
||||||
|
header @{{ service.name }}_dl{{ loop.index }} Content-Disposition `attachment; filename="{{ dl.filename }}"`
|
||||||
|
{% endfor %}
|
||||||
|
{% if service.try_html | default(false) %}
|
||||||
|
try_files {path} {path}/ {path}.html
|
||||||
|
handle_errors 404 {
|
||||||
|
rewrite * /404.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
file_server
|
||||||
|
{% else %}
|
||||||
{% if service.cache_policy | default('') == 'spa' %}
|
{% if service.cache_policy | default('') == 'spa' %}
|
||||||
# SPA cache policy: hashed static assets are immutable, HTML must revalidate.
|
# SPA cache policy: hashed static assets are immutable, HTML must revalidate.
|
||||||
# Prevents stale HTML from referencing chunk hashes that no longer exist.
|
# Prevents stale HTML from referencing chunk hashes that no longer exist.
|
||||||
|
|
@ -47,6 +66,7 @@
|
||||||
}
|
}
|
||||||
{% else %}
|
{% else %}
|
||||||
reverse_proxy {{ service.backend }}
|
reverse_proxy {{ service.backend }}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
ansible/roles/cv/defaults/main.yml
Normal file
10
ansible/roles/cv/defaults/main.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
# CV / resume static site (native, replaces minikube Deployment)
|
||||||
|
# Caddy serves cv_content_dir directly via the static-kind service block.
|
||||||
|
|
||||||
|
cv_version: "v1.0.3"
|
||||||
|
cv_release_url: "https://forge.eblu.me/api/packages/eblume/generic/cv/{{ cv_version }}/cv-{{ cv_version }}.tar.gz"
|
||||||
|
|
||||||
|
cv_home: /Users/erichblume/blumeops/cv
|
||||||
|
cv_content_dir: "{{ cv_home }}/content"
|
||||||
|
cv_version_sentinel: "{{ cv_home }}/.installed-version"
|
||||||
57
ansible/roles/cv/tasks/main.yml
Normal file
57
ansible/roles/cv/tasks/main.yml
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
# cv role — download and extract the CV release tarball into cv_content_dir.
|
||||||
|
# Caddy serves the directory directly; there is no daemon to manage.
|
||||||
|
#
|
||||||
|
# Idempotency: a sentinel file records the installed cv_version. The
|
||||||
|
# download/extract steps only run when the sentinel doesn't match cv_version.
|
||||||
|
#
|
||||||
|
# We use curl rather than ansible.builtin.get_url because the forge generic-
|
||||||
|
# packages endpoint returns 405 on HEAD requests, which get_url issues before
|
||||||
|
# downloading.
|
||||||
|
|
||||||
|
- name: Ensure cv home exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ cv_home }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Read installed cv version sentinel
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ cv_version_sentinel }}"
|
||||||
|
register: cv_installed_raw
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set installed cv version fact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cv_installed_version: >-
|
||||||
|
{{ (cv_installed_raw.content | b64decode).strip()
|
||||||
|
if (cv_installed_raw.content is defined) else '' }}
|
||||||
|
|
||||||
|
- name: Recreate cv content dir
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ cv_content_dir }}"
|
||||||
|
state: "{{ item }}"
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- absent
|
||||||
|
- directory
|
||||||
|
when: cv_installed_version != cv_version
|
||||||
|
|
||||||
|
- name: Download and extract cv release tarball
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: >-
|
||||||
|
set -euo pipefail;
|
||||||
|
curl -fsSL {{ cv_release_url | quote }} -o {{ cv_home }}/cv.tar.gz &&
|
||||||
|
tar -xzf {{ cv_home }}/cv.tar.gz -C {{ cv_content_dir }} &&
|
||||||
|
rm -f {{ cv_home }}/cv.tar.gz
|
||||||
|
executable: /bin/bash
|
||||||
|
when: cv_installed_version != cv_version
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Write cv version sentinel
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ cv_version }}\n"
|
||||||
|
dest: "{{ cv_version_sentinel }}"
|
||||||
|
mode: '0644'
|
||||||
|
when: cv_installed_version != cv_version
|
||||||
11
ansible/roles/docs/defaults/main.yml
Normal file
11
ansible/roles/docs/defaults/main.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
# Docs (Quartz-built static site) — replaces minikube Deployment.
|
||||||
|
# Caddy serves docs_content_dir directly via the static-kind service block,
|
||||||
|
# with Quartz-style try_files (path → path/ → path.html → 404).
|
||||||
|
|
||||||
|
docs_version: "v1.16.0"
|
||||||
|
docs_release_url: "https://forge.eblu.me/eblume/blumeops/releases/download/{{ docs_version }}/docs-{{ docs_version }}.tar.gz"
|
||||||
|
|
||||||
|
docs_home: /Users/erichblume/blumeops/docs
|
||||||
|
docs_content_dir: "{{ docs_home }}/content"
|
||||||
|
docs_version_sentinel: "{{ docs_home }}/.installed-version"
|
||||||
57
ansible/roles/docs/tasks/main.yml
Normal file
57
ansible/roles/docs/tasks/main.yml
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
# docs role — download and extract the Quartz-built docs tarball into
|
||||||
|
# docs_content_dir. Caddy serves the directory directly with Quartz-style
|
||||||
|
# try_files; there is no daemon to manage.
|
||||||
|
#
|
||||||
|
# Idempotency: a sentinel file records the installed docs_version. The
|
||||||
|
# download/extract steps only run when the sentinel doesn't match docs_version.
|
||||||
|
#
|
||||||
|
# Mirrors the cv role's curl-based download for consistency, even though the
|
||||||
|
# forge releases endpoint here does support HEAD.
|
||||||
|
|
||||||
|
- name: Ensure docs home exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ docs_home }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Read installed docs version sentinel
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ docs_version_sentinel }}"
|
||||||
|
register: docs_installed_raw
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set installed docs version fact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
docs_installed_version: >-
|
||||||
|
{{ (docs_installed_raw.content | b64decode).strip()
|
||||||
|
if (docs_installed_raw.content is defined) else '' }}
|
||||||
|
|
||||||
|
- name: Recreate docs content dir
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ docs_content_dir }}"
|
||||||
|
state: "{{ item }}"
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- absent
|
||||||
|
- directory
|
||||||
|
when: docs_installed_version != docs_version
|
||||||
|
|
||||||
|
- name: Download and extract docs release tarball
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: >-
|
||||||
|
set -euo pipefail;
|
||||||
|
curl -fsSL {{ docs_release_url | quote }} -o {{ docs_home }}/docs.tar.gz &&
|
||||||
|
tar -xzf {{ docs_home }}/docs.tar.gz -C {{ docs_content_dir }} &&
|
||||||
|
rm -f {{ docs_home }}/docs.tar.gz
|
||||||
|
executable: /bin/bash
|
||||||
|
when: docs_installed_version != docs_version
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Write docs version sentinel
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ docs_version }}\n"
|
||||||
|
dest: "{{ docs_version_sentinel }}"
|
||||||
|
mode: '0644'
|
||||||
|
when: docs_installed_version != docs_version
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
href: https://registry.ops.eblu.me
|
href: https://registry.ops.eblu.me
|
||||||
icon: zot-registry
|
icon: zot-registry
|
||||||
description: Container registry
|
description: Container registry
|
||||||
|
- Devpi:
|
||||||
|
href: https://pypi.ops.eblu.me
|
||||||
|
icon: mdi-language-python
|
||||||
|
description: PyPI caching mirror
|
||||||
- Sifaka NAS:
|
- Sifaka NAS:
|
||||||
href: https://nas.ops.eblu.me
|
href: https://nas.ops.eblu.me
|
||||||
icon: synology
|
icon: synology
|
||||||
|
|
@ -77,3 +81,15 @@
|
||||||
href: https://ntfy.ops.eblu.me
|
href: https://ntfy.ops.eblu.me
|
||||||
icon: ntfy.png
|
icon: ntfy.png
|
||||||
description: Push notifications
|
description: Push notifications
|
||||||
|
- Services:
|
||||||
|
# CV and Docs were previously auto-discovered from k8s Ingresses; after
|
||||||
|
# the indri-native migration ([[cv-on-indri]], [[docs-on-indri]]) there
|
||||||
|
# is no Ingress to discover, so they live here as static entries.
|
||||||
|
- CV:
|
||||||
|
href: https://cv.eblu.me
|
||||||
|
icon: mdi-file-document
|
||||||
|
description: Resume / CV
|
||||||
|
- Docs:
|
||||||
|
href: https://docs.eblu.me
|
||||||
|
icon: mdi-book-open-page-variant
|
||||||
|
description: BlumeOps Documentation
|
||||||
|
|
|
||||||
1
docs/changelog.d/migrate-cv-docs-to-indri.infra.md
Normal file
1
docs/changelog.d/migrate-cv-docs-to-indri.infra.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Migrated CV (`cv.eblu.me`) and Docs (`docs.eblu.me`) from minikube Deployments to indri-native ansible roles. Caddy now serves the extracted release tarballs directly via a new `kind: static` service-block in the Caddy template — no daemon, no container — replacing the prior nginx-in-a-pod layer. Removes a network hop on every request and shrinks minikube's footprint. See [[cv-on-indri]] and [[docs-on-indri]]. Part of the broader minikube wind-down.
|
||||||
72
docs/how-to/operations/cv-on-indri.md
Normal file
72
docs/how-to/operations/cv-on-indri.md
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
---
|
||||||
|
title: CV on Indri
|
||||||
|
modified: 2026-04-29
|
||||||
|
last-reviewed: 2026-04-29
|
||||||
|
tags:
|
||||||
|
- how-to
|
||||||
|
- operations
|
||||||
|
---
|
||||||
|
|
||||||
|
# CV on Indri
|
||||||
|
|
||||||
|
How the CV/resume static site (`cv.eblu.me`) is deployed on indri natively. Replaces the prior minikube Deployment; mirrors the rationale of [[devpi-on-indri]].
|
||||||
|
|
||||||
|
## Why native, not Kubernetes
|
||||||
|
|
||||||
|
CV is a tiny static site (HTML + CSS + PDF). It needs no daemon, no database, no auth. Caddy on indri can serve the extracted tarball directly via `file_server`. Removing the minikube Deployment shrinks the cluster's footprint and removes a network hop (Fly → indri Caddy → ProxyGroup ingress → minikube pod becomes Fly → indri Caddy → local files).
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
| Concern | Path / detail |
|
||||||
|
|---|---|
|
||||||
|
| Content dir | `/Users/erichblume/blumeops/cv/content/` |
|
||||||
|
| Version sentinel | `/Users/erichblume/blumeops/cv/.installed-version` |
|
||||||
|
| Caddy entry | `cv` service in `ansible/roles/caddy/defaults/main.yml` (`kind: static`) |
|
||||||
|
| Public URL | `https://cv.eblu.me` (via [[flyio-proxy]]) |
|
||||||
|
| Private URL | `https://cv.ops.eblu.me` (Caddy on indri) |
|
||||||
|
| Tarball source | Forgejo generic package `cv` (`forge.eblu.me/eblume/-/packages`) |
|
||||||
|
|
||||||
|
The role is driven by `cv_version` in `ansible/roles/cv/defaults/main.yml`. The download and extract steps only fire when the on-disk sentinel doesn't match `cv_version` — i.e. after a version bump.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
Two paths:
|
||||||
|
|
||||||
|
**From a release workflow** (most common):
|
||||||
|
|
||||||
|
1. Run the `Release CV` workflow in the cv repo → produces a new generic package
|
||||||
|
2. Run the blumeops `Deploy CV` workflow → bumps `cv_version` in `ansible/roles/cv/defaults/main.yml` and pushes to main
|
||||||
|
3. From gilbert: `mise run provision-indri -- --tags cv`
|
||||||
|
4. From gilbert: `fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'"` to purge the public-edge cache
|
||||||
|
|
||||||
|
**Manual** (e.g., reverting): edit `cv_version` in the role defaults yourself, then steps 3–4.
|
||||||
|
|
||||||
|
## Verify
|
||||||
|
|
||||||
|
```fish
|
||||||
|
ssh indri 'cat ~/blumeops/cv/.installed-version'
|
||||||
|
ssh indri 'ls -la ~/blumeops/cv/content/'
|
||||||
|
curl -fsSI https://cv.ops.eblu.me/ # private
|
||||||
|
curl -fsSI https://cv.eblu.me/ # public
|
||||||
|
curl -fsSI https://cv.eblu.me/resume.pdf | grep -i disposition
|
||||||
|
```
|
||||||
|
|
||||||
|
The PDF response should include `content-disposition: attachment; filename="erich-blume-resume.pdf"`.
|
||||||
|
|
||||||
|
## Bumping the cv version
|
||||||
|
|
||||||
|
Edit `cv_version` in `ansible/roles/cv/defaults/main.yml` and re-run `mise run provision-indri -- --tags cv`. The role recreates the content dir from the new tarball; the sentinel update triggers the next idempotent skip.
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
|
||||||
|
The content dir is **not** in `borgmatic_source_directories`. The tarball is re-downloadable from the Forgejo generic package store on every deploy, and the source is in the cv repo — recovery is just re-running the role.
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
If a bad version is published, set `cv_version` back to the previous tag in `ansible/roles/cv/defaults/main.yml` and re-run the role. The full minikube manifest set is preserved in git history (commits prior to the migration cleanup) for the worst case.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[devpi-on-indri]] — same shape, different upstream
|
||||||
|
- [[restart-indri]] — graceful indri restart procedure
|
||||||
|
- [[cv]] — service reference
|
||||||
66
docs/how-to/operations/docs-on-indri.md
Normal file
66
docs/how-to/operations/docs-on-indri.md
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
title: Docs on Indri
|
||||||
|
modified: 2026-04-29
|
||||||
|
last-reviewed: 2026-04-29
|
||||||
|
tags:
|
||||||
|
- how-to
|
||||||
|
- operations
|
||||||
|
---
|
||||||
|
|
||||||
|
# Docs on Indri
|
||||||
|
|
||||||
|
How the Quartz documentation site (`docs.eblu.me`) is deployed on indri natively. Replaces the prior minikube Deployment; same shape as [[cv-on-indri]] with one extra wrinkle for Quartz's clean URLs.
|
||||||
|
|
||||||
|
## Why native, not Kubernetes
|
||||||
|
|
||||||
|
The docs site is fully static HTML produced by Quartz. Caddy can serve the extracted tarball directly. The Quartz-specific behavior the previous nginx container provided (`try_files $uri $uri/ $uri.html =404` and a custom `/404.html`) maps cleanly to Caddy's `try_files` and `handle_errors`.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
| Concern | Path / detail |
|
||||||
|
|---|---|
|
||||||
|
| Content dir | `/Users/erichblume/blumeops/docs/content/` |
|
||||||
|
| Version sentinel | `/Users/erichblume/blumeops/docs/.installed-version` |
|
||||||
|
| Caddy entry | `docs` service in `ansible/roles/caddy/defaults/main.yml` (`kind: static`, `try_html: true`) |
|
||||||
|
| Public URL | `https://docs.eblu.me` (via [[flyio-proxy]]) |
|
||||||
|
| Private URL | `https://docs.ops.eblu.me` (Caddy on indri) |
|
||||||
|
| Tarball source | Forgejo release asset on the blumeops repo (`docs-<version>.tar.gz`) |
|
||||||
|
|
||||||
|
`docs_version` in `ansible/roles/docs/defaults/main.yml` is the blumeops release tag (e.g. `v1.16.0`). The role's download/extract is gated by an on-disk sentinel.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
1. Run the `Build BlumeOps` Forgejo workflow → builds the tarball, creates a release, bumps `docs_version` in the ansible role, pushes to main
|
||||||
|
2. From gilbert: `mise run provision-indri -- --tags docs`
|
||||||
|
3. From gilbert: `fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'"`
|
||||||
|
|
||||||
|
The Caddy block uses `try_files {path} {path}/ {path}.html` and a `handle_errors 404 → /404.html` rewrite, matching the original nginx behavior so Quartz's clean URLs continue to work.
|
||||||
|
|
||||||
|
## Verify
|
||||||
|
|
||||||
|
```fish
|
||||||
|
ssh indri 'cat ~/blumeops/docs/.installed-version'
|
||||||
|
ssh indri 'ls ~/blumeops/docs/content/'
|
||||||
|
curl -fsSI https://docs.ops.eblu.me/ # private
|
||||||
|
curl -fsSI https://docs.eblu.me/ # public
|
||||||
|
curl -fsSI https://docs.eblu.me/explanation/agent-change-process # clean URL → .html fallback
|
||||||
|
curl -fsSI https://docs.eblu.me/no-such-path-exists/ # → /404.html
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bumping the docs version
|
||||||
|
|
||||||
|
Normally driven by the workflow. If you need to pin manually, edit `docs_version` in `ansible/roles/docs/defaults/main.yml` and re-run `mise run provision-indri -- --tags docs`.
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
|
||||||
|
Content dir is not borgmatic-backed. Source is in this repo; release tarballs are on the forge.
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
Set `docs_version` back to the previous release tag in the role defaults and re-run. Older release tarballs remain available as Forgejo release assets.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[cv-on-indri]] — sibling service, simpler (no `try_html`)
|
||||||
|
- [[devpi-on-indri]] — pattern reference for indri-native services
|
||||||
|
- [[docs]] — service reference
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: CV
|
title: CV
|
||||||
modified: 2026-03-27
|
modified: 2026-04-29
|
||||||
last-reviewed: 2026-03-27
|
last-reviewed: 2026-04-29
|
||||||
tags:
|
tags:
|
||||||
- service
|
- service
|
||||||
- resume
|
- resume
|
||||||
|
|
@ -15,37 +15,36 @@ Personal resume/CV served as a static HTML page with PDF download, built from YA
|
||||||
|
|
||||||
| Property | Value |
|
| Property | Value |
|
||||||
|----------|-------|
|
|----------|-------|
|
||||||
| **URL** | `cv.eblu.me` (public, via [[flyio-proxy]]) |
|
| **Public URL** | `cv.eblu.me` (via [[flyio-proxy]]) |
|
||||||
| **Namespace** | `cv` |
|
| **Private URL** | `cv.ops.eblu.me` (Caddy on indri) |
|
||||||
| **Container** | `registry.ops.eblu.me/blumeops/cv` ([kustomization](https://forge.eblu.me/eblume/blumeops/src/branch/main/argocd/manifests/cv/kustomization.yaml)) |
|
| **Deployment** | Ansible role `cv` on indri (no daemon — Caddy serves files directly) |
|
||||||
|
| **Content dir** | `~/blumeops/cv/content/` on indri |
|
||||||
| **Source repo** | `forge.eblu.me/eblume/cv` (private, not mirrored to GitHub) |
|
| **Source repo** | `forge.eblu.me/eblume/cv` (private, not mirrored to GitHub) |
|
||||||
| **Content packages** | `forge.eblu.me/eblume/-/packages` (generic package `cv`) |
|
| **Content packages** | `forge.eblu.me/eblume/-/packages` (generic package `cv`) |
|
||||||
| **ArgoCD App** | `cv` |
|
|
||||||
|
Migrated from minikube to indri-native on 2026-04-29 (see [[cv-on-indri]]).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
1. **Source**: `resume.yaml` (content) + `template.html` (Jinja2) + `style.css` in the cv repo
|
1. **Source**: `resume.yaml` (content) + `template.html` (Jinja2) + `style.css` in the cv repo
|
||||||
2. **Build**: `render.py` (uv script runner) generates `index.html`; WeasyPrint generates `resume.pdf`
|
2. **Build**: `render.py` (uv script runner) generates `index.html`; WeasyPrint generates `resume.pdf`
|
||||||
3. **Release**: Dagger `build` function packages `index.html`, `style.css`, `resume.pdf` into a tarball, uploaded to Forgejo generic packages
|
3. **Release**: Dagger `build` function packages `index.html`, `style.css`, `resume.pdf` into a tarball, uploaded to Forgejo generic packages
|
||||||
4. **Deploy**: nginx container downloads the tarball at startup via `CV_RELEASE_URL` env var
|
4. **Deploy**: ansible role downloads the tarball into `~/blumeops/cv/content/` on indri; Caddy serves the directory directly
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
| Path | Description |
|
| Path | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `/` | Resume HTML page |
|
| `/` | Resume HTML page |
|
||||||
| `/resume.pdf` | PDF download (Content-Disposition: attachment) |
|
| `/resume.pdf` | PDF download (Caddy adds `Content-Disposition: attachment`) |
|
||||||
| `/healthz` | Health check (200 OK) |
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
**Key files (blumeops):**
|
**Key files (blumeops):**
|
||||||
|
|
||||||
- `containers/cv/Dockerfile` — nginx:alpine container
|
- `ansible/roles/cv/defaults/main.yml` — pinned `cv_version` and tarball URL
|
||||||
- `containers/cv/start.sh` — tarball download + extraction
|
- `ansible/roles/cv/tasks/main.yml` — sentinel-gated download + extract
|
||||||
- `containers/cv/default.conf` — nginx config (gzip, caching, PDF headers)
|
- `ansible/roles/caddy/defaults/main.yml` — `cv` service entry (`kind: static`, `download_paths` for the PDF)
|
||||||
- `argocd/manifests/cv/deployment.yaml` — `CV_RELEASE_URL` env var
|
|
||||||
- `argocd/apps/cv.yaml` — ArgoCD Application
|
|
||||||
|
|
||||||
**Key files (cv repo):**
|
**Key files (cv repo):**
|
||||||
|
|
||||||
|
|
@ -56,17 +55,15 @@ Personal resume/CV served as a static HTML page with PDF download, built from YA
|
||||||
- `src/cv_ci/main.py` — Dagger pipeline (alpine + uv + WeasyPrint)
|
- `src/cv_ci/main.py` — Dagger pipeline (alpine + uv + WeasyPrint)
|
||||||
- `.forgejo/workflows/cv-release.yaml` — Release workflow
|
- `.forgejo/workflows/cv-release.yaml` — Release workflow
|
||||||
|
|
||||||
## Secrets
|
## Release flow
|
||||||
|
|
||||||
| Secret | Repo | Source | Description |
|
1. Release a new package from the cv repo (`Release CV` workflow)
|
||||||
|--------|------|--------|-------------|
|
2. Run the blumeops `Deploy CV` workflow → bumps `cv_version` in the ansible role and pushes
|
||||||
| `FORGE_TOKEN` | cv | 1Password (via Ansible) | Forgejo API token for package uploads |
|
3. Run `mise run provision-indri -- --tags cv` from gilbert
|
||||||
|
4. Purge the Fly.io proxy cache so the new content is fetched
|
||||||
Provisioned via `forgejo_actions_secrets` Ansible role. See [[create-release-artifact-workflow]].
|
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [[docs]] — Similar architecture (nginx container + content tarball)
|
- [[cv-on-indri]] — Operations how-to
|
||||||
|
- [[docs]] — Similar architecture (Caddy serving a tarball-extracted dir)
|
||||||
- [[flyio-proxy]] — Exposes `cv.eblu.me` publicly via Tailscale tunnel
|
- [[flyio-proxy]] — Exposes `cv.eblu.me` publicly via Tailscale tunnel
|
||||||
- [[create-release-artifact-workflow]] — How to set up release artifact workflows
|
|
||||||
- [[deploy-k8s-service]] — General k8s deployment guide
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Docs
|
title: Docs
|
||||||
modified: 2026-03-23
|
modified: 2026-04-29
|
||||||
last-reviewed: 2026-03-23
|
last-reviewed: 2026-04-29
|
||||||
tags:
|
tags:
|
||||||
- service
|
- service
|
||||||
- documentation
|
- documentation
|
||||||
|
|
@ -9,44 +9,42 @@ tags:
|
||||||
|
|
||||||
# Docs (Quartz)
|
# Docs (Quartz)
|
||||||
|
|
||||||
Documentation site built with [Quartz](https://quartz.jzhao.xyz/) and served via nginx.
|
Documentation site built with [Quartz](https://quartz.jzhao.xyz/).
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
| Property | Value |
|
| Property | Value |
|
||||||
|----------|-------|
|
|----------|-------|
|
||||||
| **Public URL** | https://docs.eblu.me |
|
| **Public URL** | https://docs.eblu.me (via [[flyio-proxy]]) |
|
||||||
| **Private URL** | `docs.ops.eblu.me` (tailnet only, via [[caddy]]) |
|
| **Private URL** | `docs.ops.eblu.me` (Caddy on indri) |
|
||||||
| **Namespace** | `docs` |
|
| **Deployment** | Ansible role `docs` on indri (no daemon — Caddy serves files directly) |
|
||||||
| **Image** | `registry.ops.eblu.me/blumeops/quartz` (see `argocd/manifests/docs/kustomization.yaml` for current tag) |
|
| **Content dir** | `~/blumeops/docs/content/` on indri |
|
||||||
| **Source** | `docs/` directory in blumeops repo |
|
| **Source** | `docs/` directory in blumeops repo |
|
||||||
| **Build** | Forgejo workflow `build-blumeops.yaml` |
|
| **Build** | Forgejo workflow `build-blumeops.yaml` |
|
||||||
| **Public proxy** | [[flyio-proxy]] (Fly.io → Tailscale tunnel) |
|
|
||||||
|
Migrated from minikube to indri-native on 2026-04-29 (see [[docs-on-indri]]).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
1. **Source**: Markdown files in `docs/` with Obsidian-compatible wiki-links
|
1. **Source**: Markdown files in `docs/` with Obsidian-compatible wiki-links
|
||||||
2. **Build**: Forgejo workflow builds Quartz static site on push to main
|
2. **Build**: `Build BlumeOps` Forgejo workflow runs towncrier + Quartz, uploads tarball as a release asset, and bumps `docs_version` in the ansible role
|
||||||
3. **Release**: Built assets published as Forgejo release attachments
|
3. **Deploy**: ansible role downloads the tarball into `~/blumeops/docs/content/` on indri; Caddy serves the directory directly with Quartz-style `try_files` (path → path/ → path.html → 404.html)
|
||||||
4. **Deploy**: Container downloads release bundle on startup, serves via nginx
|
|
||||||
|
|
||||||
## Release Process
|
|
||||||
|
|
||||||
Documentation is built and released via the `build-blumeops` Forgejo workflow (manual dispatch):
|
|
||||||
|
|
||||||
1. Quartz builds static HTML/CSS/JS
|
|
||||||
2. Assets uploaded as Forgejo release attachment
|
|
||||||
3. Workflow updates `DOCS_RELEASE_URL` in `argocd/manifests/docs/deployment.yaml` and commits to main
|
|
||||||
4. ArgoCD syncs the updated deployment; new pod downloads the release bundle at startup
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
- **Quartz config**: `quartz.config.ts`
|
- **Quartz config**: `quartz.config.ts`
|
||||||
- **Layout**: `quartz.layout.ts`
|
- **Layout**: `quartz.layout.ts`
|
||||||
- **ArgoCD app**: `argocd/apps/docs.yaml`
|
- **Ansible role**: `ansible/roles/docs/`
|
||||||
- **Manifests**: `argocd/manifests/docs/`
|
- **Caddy entry**: `ansible/roles/caddy/defaults/main.yml` (`kind: static`, `try_html: true`)
|
||||||
|
|
||||||
|
## Release flow
|
||||||
|
|
||||||
|
1. Run the `Build BlumeOps` workflow → builds tarball, creates release, bumps `docs_version` in the ansible role and pushes
|
||||||
|
2. Run `mise run provision-indri -- --tags docs` from gilbert
|
||||||
|
3. Purge the Fly.io proxy cache so the new content is fetched
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [[argocd]] - Deployment management
|
- [[docs-on-indri]] — Operations how-to
|
||||||
- [[forgejo]] - Build workflows
|
- [[cv]] — Similar architecture
|
||||||
|
- [[forgejo]] — Build workflows
|
||||||
|
|
|
||||||
|
|
@ -221,18 +221,26 @@ services:
|
||||||
notes: Installed via uv into a venv on indri; version pinned in ansible/roles/devpi/defaults/main.yml
|
notes: Installed via uv into a venv on indri; version pinned in ansible/roles/devpi/defaults/main.yml
|
||||||
|
|
||||||
- name: cv
|
- name: cv
|
||||||
type: argocd
|
type: ansible
|
||||||
last-reviewed: 2026-04-27
|
last-reviewed: 2026-04-29
|
||||||
current-version: "1.0.3"
|
current-version: "1.0.3"
|
||||||
upstream-source: https://forge.eblu.me/eblume/cv
|
upstream-source: https://forge.eblu.me/eblume/cv
|
||||||
notes: Personal static site; review build deps (WeasyPrint, Jinja2) in source repo
|
notes: >-
|
||||||
|
Static tarball downloaded by ansible/roles/cv into ~/blumeops/cv/content on indri;
|
||||||
|
served directly by Caddy (kind=static). Migrated from minikube 2026-04-29.
|
||||||
|
Review build deps (WeasyPrint, Jinja2) in source repo on upstream review.
|
||||||
|
|
||||||
- name: docs
|
- name: docs
|
||||||
type: argocd
|
type: ansible
|
||||||
last-reviewed: 2026-03-07
|
last-reviewed: 2026-04-29
|
||||||
current-version: "1.28.2"
|
current-version: "1.28.2"
|
||||||
upstream-source: https://github.com/jackyzha0/quartz/releases
|
upstream-source: https://forge.eblu.me/eblume/blumeops/releases
|
||||||
notes: Quartz static site generator; container version tracks nginx base
|
notes: >-
|
||||||
|
Quartz-built tarball downloaded by ansible/roles/docs into ~/blumeops/docs/content
|
||||||
|
on indri; served directly by Caddy (kind=static, try_html). Migrated from
|
||||||
|
minikube 2026-04-29. current-version still tracks the legacy quartz/nginx
|
||||||
|
base; will switch to the docs release tag (e.g. v1.16.0) once the dead
|
||||||
|
containers/quartz Dockerfile is removed in the cleanup commit.
|
||||||
|
|
||||||
- name: forgejo-runner
|
- name: forgejo-runner
|
||||||
type: argocd
|
type: argocd
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue