Fix build version showing "unknown" in production
The previous approach baked git rev-parse --short HEAD into the image at Docker build time, but Dockhand's build context doesn't reliably have .git available, so it silently fell back to "unknown" in production even though the build itself succeeded. Replace it with a plain VERSION file committed to the repo (a timestamp + short description, updated by hand alongside each commit) that ships via the same COPY . . as everything else - no git access needed inside the build at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+1
-4
@@ -1,8 +1,5 @@
|
|||||||
# Version control
|
# Version control
|
||||||
# .git is intentionally NOT excluded - the Dockerfile reads it at build
|
.git
|
||||||
# time (git rev-parse) to bake the running commit into the image as
|
|
||||||
# /app/BUILD_VERSION, then deletes .git itself in that same build step so
|
|
||||||
# it never ends up in the final image.
|
|
||||||
.gitignore
|
.gitignore
|
||||||
.github
|
.github
|
||||||
|
|
||||||
|
|||||||
+2
-12
@@ -5,9 +5,8 @@ FROM python:3.13.5-slim-bookworm
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# ffprobe (from ffmpeg) reads each video's duration for the library
|
# ffprobe (from ffmpeg) reads each video's duration for the library
|
||||||
# browser's "how long is this course" display; git is only needed
|
# browser's "how long is this course" display
|
||||||
# transiently below, to bake this build's commit into the image
|
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg \
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg git \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# copy the dependencies file to the working directory
|
# copy the dependencies file to the working directory
|
||||||
@@ -20,15 +19,6 @@ RUN pip install -r requirements.txt
|
|||||||
# copy the content of the local src directory to the working directory
|
# copy the content of the local src directory to the working directory
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Record which commit and when this image was built, so the running app
|
|
||||||
# can show it (Settings page, /health) - a full-image-rebuild webhook
|
|
||||||
# deploy gives no other visible confirmation that a push actually landed
|
|
||||||
# in the running container. .git is removed right after so the image
|
|
||||||
# doesn't carry the repo's full history.
|
|
||||||
RUN (git rev-parse --short HEAD 2>/dev/null || echo unknown) > /app/BUILD_VERSION \
|
|
||||||
&& date -u +"%Y-%m-%d %H:%M UTC" >> /app/BUILD_VERSION \
|
|
||||||
&& rm -rf /app/.git
|
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
# add healthcheck using Python standard library
|
# add healthcheck using Python standard library
|
||||||
|
|||||||
@@ -44,13 +44,16 @@ triggers a full image **rebuild** from the Dockerfile (confirmed, not just a
|
|||||||
container restart), so Dockerfile changes (e.g. adding `ffmpeg`) take effect
|
container restart), so Dockerfile changes (e.g. adding `ffmpeg`) take effect
|
||||||
on the very next push without any manual step.
|
on the very next push without any manual step.
|
||||||
|
|
||||||
**Confirming a deploy landed:** the Dockerfile bakes the exact commit and
|
**Confirming a deploy landed:** a plain `VERSION` file at the repo root
|
||||||
build time into the image as `/app/BUILD_VERSION` (`git rev-parse` at build
|
(a timestamp + short description, updated by hand alongside each commit)
|
||||||
time, `.git` itself is deleted again right after so it doesn't ship in the
|
ships into the image via the normal `COPY . .` and is shown at the bottom
|
||||||
image) - shown at the bottom of the Settings page and in `/health`'s JSON
|
of the Settings page and in `/health`'s JSON response, so after a push you
|
||||||
response, so after a push you can check the running container actually
|
can check the running container actually picked it up instead of
|
||||||
picked it up instead of guessing. Reads as `dev` outside Docker (no
|
guessing. Deliberately not derived from `git rev-parse` at Docker build
|
||||||
`BUILD_VERSION` file to read).
|
time - Dockhand's build context doesn't reliably have `.git` available,
|
||||||
|
which silently produced "unknown" instead of an actual commit. Reads as
|
||||||
|
`dev` outside Docker (no `VERSION` file to read, e.g. before the first
|
||||||
|
commit that adds one).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+14
-13
@@ -33,22 +33,23 @@ app.config['SECRET_KEY'] = 'your-secret-key-change-in-production'
|
|||||||
|
|
||||||
def _load_build_version() -> str:
|
def _load_build_version() -> str:
|
||||||
"""
|
"""
|
||||||
Commit + build time baked into the image at build time (see
|
Reads the repo-committed VERSION file - lets Settings and /health show
|
||||||
Dockerfile) - lets Settings and /health show which version is
|
which version is actually running, the only way to confirm a push made
|
||||||
actually running, the only way to confirm a git push made it into a
|
it into a rebuilt container, since the webhook does a full image
|
||||||
rebuilt container, since the webhook does a full image rebuild with
|
rebuild with no other visible confirmation. Deliberately a plain file
|
||||||
no other visible confirmation. Falls back to 'dev' outside Docker,
|
checked into the repo (updated by hand alongside each commit) rather
|
||||||
where there's no BUILD_VERSION file (e.g. running via --library-path
|
than baked from `git rev-parse` at Docker build time: Dockhand's build
|
||||||
directly).
|
context doesn't reliably have .git available, which silently produced
|
||||||
|
"unknown" instead of a real commit. Falls back to 'dev' if the file is
|
||||||
|
ever missing (shouldn't happen once committed, since it ships via the
|
||||||
|
same COPY . . as everything else).
|
||||||
"""
|
"""
|
||||||
version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'BUILD_VERSION')
|
version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'VERSION')
|
||||||
try:
|
try:
|
||||||
with open(version_file, 'r') as f:
|
with open(version_file, 'r') as f:
|
||||||
lines = [line.strip() for line in f if line.strip()]
|
content = f.read().strip()
|
||||||
if len(lines) >= 2:
|
if content:
|
||||||
return f'{lines[0]} · built {lines[1]}'
|
return content
|
||||||
if lines:
|
|
||||||
return lines[0]
|
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
return 'dev'
|
return 'dev'
|
||||||
|
|||||||
Reference in New Issue
Block a user