Add auto-incrementing version display to web UI footer
Exposes GET /version endpoint in the web container (reads APP_VERSION env var). CI computes the version as 1.0.<git-commit-count> and passes it via --build-arg at build time. Both index.html and cv-matcher/index.html show the version in the footer via a JS fetch. docker-compose passes APP_VERSION through to the running container. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Build Web image
|
- name: Build Web image
|
||||||
run: |
|
run: |
|
||||||
docker build -f web/Dockerfile -t "${REGISTRY_HOST}/${WEB_IMAGE}:${IMAGE_TAG}" .
|
APP_VERSION="1.0.$(git rev-list --count HEAD)"
|
||||||
|
docker build -f web/Dockerfile \
|
||||||
|
--build-arg APP_VERSION="${APP_VERSION}" \
|
||||||
|
-t "${REGISTRY_HOST}/${WEB_IMAGE}:${IMAGE_TAG}" .
|
||||||
|
|
||||||
- name: Build CV cleanup job image
|
- name: Build CV cleanup job image
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
# For local dev this is ignored (docker-compose.override.yml builds images locally).
|
# For local dev this is ignored (docker-compose.override.yml builds images locally).
|
||||||
IMAGE_TAG=staging
|
IMAGE_TAG=staging
|
||||||
|
|
||||||
|
# Application version displayed in the web UI footer.
|
||||||
|
# CI sets this automatically to 1.0.<git-commit-count> at build time.
|
||||||
|
APP_VERSION=1.0.0
|
||||||
|
|
||||||
# Volume base paths — controls where logs and uploaded files are stored on the host.
|
# Volume base paths — controls where logs and uploaded files are stored on the host.
|
||||||
# Portainer (staging/prod): leave unset to use the /opt/myai defaults.
|
# Portainer (staging/prod): leave unset to use the /opt/myai defaults.
|
||||||
# Local dev: set to relative paths so logs and files land in the repo tree.
|
# Local dev: set to relative paths so logs and files land in the repo tree.
|
||||||
|
|||||||
@@ -263,6 +263,7 @@ services:
|
|||||||
- ASPNETCORE_URLS=${ASPNETCORE_URLS:-http://+:8080}
|
- ASPNETCORE_URLS=${ASPNETCORE_URLS:-http://+:8080}
|
||||||
- APP_ENVIRONMENT_NAME=${APP_ENVIRONMENT_NAME:-myai.staging}
|
- APP_ENVIRONMENT_NAME=${APP_ENVIRONMENT_NAME:-myai.staging}
|
||||||
|
|
||||||
|
- APP_VERSION=${APP_VERSION:-unknown}
|
||||||
- Site__Mode=${Site__Mode:-Normal}
|
- Site__Mode=${Site__Mode:-Normal}
|
||||||
networks:
|
networks:
|
||||||
- myai-network
|
- myai-network
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
ENV ASPNETCORE_URLS=http://0.0.0.0:8080
|
ENV ASPNETCORE_URLS=http://0.0.0.0:8080
|
||||||
|
ARG APP_VERSION=1.0.0
|
||||||
|
ENV APP_VERSION=${APP_VERSION}
|
||||||
|
|
||||||
COPY --from=build /app/publish .
|
COPY --from=build /app/publish .
|
||||||
ENTRYPOINT ["dotnet", "web.dll"]
|
ENTRYPOINT ["dotnet", "web.dll"]
|
||||||
@@ -14,6 +14,9 @@ var app = builder.Build();
|
|||||||
|
|
||||||
app.UseMiddleware<SiteModeMiddleware>();
|
app.UseMiddleware<SiteModeMiddleware>();
|
||||||
|
|
||||||
|
app.MapGet("/version", (IConfiguration config) =>
|
||||||
|
Results.Json(new { version = config["APP_VERSION"] ?? "unknown" }));
|
||||||
|
|
||||||
// Static site
|
// Static site
|
||||||
app.UseDefaultFiles();
|
app.UseDefaultFiles();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|||||||
@@ -607,6 +607,13 @@ img {
|
|||||||
flex-wrap: wrap
|
flex-wrap: wrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-version {
|
||||||
|
font-size: .7rem;
|
||||||
|
color: var(--muted);
|
||||||
|
opacity: .5;
|
||||||
|
font-family: monospace
|
||||||
|
}
|
||||||
|
|
||||||
.cookie-overlay {
|
.cookie-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|||||||
@@ -186,6 +186,7 @@
|
|||||||
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="legal.privacy">Privacy</a>
|
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="legal.privacy">Privacy</a>
|
||||||
<a data-legal="cookies" href="/legal/cookies-en.html" target="_blank" data-i18n="legal.cookies">Cookies</a>
|
<a data-legal="cookies" href="/legal/cookies-en.html" target="_blank" data-i18n="legal.cookies">Cookies</a>
|
||||||
</div>
|
</div>
|
||||||
|
<span id="app-version" class="app-version"></span>
|
||||||
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow" data-i18n="footer.top">Back to top</a>
|
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow" data-i18n="footer.top">Back to top</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -189,6 +189,7 @@
|
|||||||
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="legal.privacy">Privacy</a>
|
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="legal.privacy">Privacy</a>
|
||||||
<a data-legal="cookies" href="/legal/cookies-en.html" target="_blank" data-i18n="legal.cookies">Cookies</a>
|
<a data-legal="cookies" href="/legal/cookies-en.html" target="_blank" data-i18n="legal.cookies">Cookies</a>
|
||||||
</div>
|
</div>
|
||||||
|
<span id="app-version" class="app-version"></span>
|
||||||
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow" data-i18n="footer.top">Back to top</a>
|
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow" data-i18n="footer.top">Back to top</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -262,6 +262,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$('#year').text(new Date().getFullYear());
|
$('#year').text(new Date().getFullYear());
|
||||||
|
|
||||||
|
$.getJSON('/version').done(function (data) {
|
||||||
|
if (data && data.version) {
|
||||||
|
$('#app-version').text('v' + data.version);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
applyLanguage(currentLang());
|
applyLanguage(currentLang());
|
||||||
$('.lang-flag').on('click', function () {
|
$('.lang-flag').on('click', function () {
|
||||||
applyLanguage($(this).data('lang'));
|
applyLanguage($(this).data('lang'));
|
||||||
|
|||||||
Reference in New Issue
Block a user