1 Commits

Author SHA1 Message Date
3c1604c7af feat: Bake build metadata (git tag, commit, date) into OCI image and display in web UI
Some checks failed
Deploy to K8s / deploy (push) Failing after 10s
Build and Push / build (push) Successful in 6s
Store git tag, commit hash, and build date as OCI-standard labels and a
build_meta.json file inside the Docker image. The Flask app reads this at
startup and displays version info in all page footers. Adds /version JSON
endpoint for programmatic access. Falls back to dev@local outside Docker.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:30:20 +01:00
10 changed files with 35 additions and 9 deletions

View File

@@ -45,7 +45,11 @@ web-debug: $(PYTHON)
FLASK_DEBUG=1 $(PYTHON) app.py
image:
docker build -t fuj-management:latest -f build/Dockerfile .
docker build -t fuj-management:latest \
--build-arg GIT_TAG=$$(git describe --tags --always 2>/dev/null || echo "untagged") \
--build-arg GIT_COMMIT=$$(git rev-parse --short HEAD) \
--build-arg BUILD_DATE=$$(date -u +%Y-%m-%dT%H:%M:%SZ) \
-f build/Dockerfile .
run:
docker run -it --rm -p 5001:5001 -v $(CURDIR)/.secret:/app/.secret:ro fuj-management:latest

13
app.py
View File

@@ -72,6 +72,13 @@ def warmup_cache():
logger.info("Cache warmup complete.")
app = Flask(__name__)
import json as _json
_meta_path = Path(__file__).parent / "build_meta.json"
BUILD_META = _json.loads(_meta_path.read_text()) if _meta_path.exists() else {
"tag": "dev", "commit": "local", "build_date": ""
}
warmup_cache()
@app.before_request
@@ -101,7 +108,7 @@ def inject_render_time():
"total": f"{total:.3f}",
"breakdown": " | ".join(breakdown)
}
return dict(get_render_time=get_render_time)
return dict(get_render_time=get_render_time, build_meta=BUILD_META)
@app.route("/")
def index():
@@ -113,6 +120,10 @@ def flush_cache_endpoint():
deleted = flush_cache()
return jsonify({"status": "ok", "deleted_files": deleted})
@app.route("/version")
def version():
return BUILD_META
@app.route("/fees")
def fees():
attendance_url = f"https://docs.google.com/spreadsheets/d/{ATTENDANCE_SHEET_ID}/edit"

View File

@@ -24,6 +24,17 @@ COPY templates/ ./templates/
COPY build/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ARG GIT_TAG=unknown
ARG GIT_COMMIT=unknown
ARG BUILD_DATE=unknown
LABEL org.opencontainers.image.version="${GIT_TAG}" \
org.opencontainers.image.revision="${GIT_COMMIT}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.title="fuj-management"
RUN echo "{\"tag\": \"${GIT_TAG}\", \"commit\": \"${GIT_COMMIT}\", \"build_date\": \"${BUILD_DATE}\"}" > /app/build_meta.json
EXPOSE 5001
HEALTHCHECK --interval=60s --timeout=5s --start-period=5s \

View File

@@ -647,7 +647,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>

View File

@@ -238,7 +238,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>

View File

@@ -253,7 +253,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>

View File

@@ -628,7 +628,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>

View File

@@ -237,7 +237,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>

View File

@@ -631,7 +631,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>

View File

@@ -631,7 +631,7 @@
{% set rt = get_render_time() %}
<div class="footer"
onclick="document.getElementById('perf-details').style.display = (document.getElementById('perf-details').style.display === 'block' ? 'none' : 'block')">
render time: {{ rt.total }}s
{{ build_meta.tag }}@{{ build_meta.commit }} | render time: {{ rt.total }}s
<div id="perf-details" class="perf-breakdown">
{{ rt.breakdown }}
</div>