Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: get version info in Docker image #29

Merged
merged 3 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ jobs:
steps:
- name: Checkout branch
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
with:
fetch-depth: 0

- name: Login into GHCR
if: github.ref_name == 'main'
Expand All @@ -44,6 +46,7 @@ jobs:
id: build-and-push
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
with:
context: .
push: ${{ github.ref_name == 'main' }}
file: Dockerfile
tags: ${{ steps.meta.outputs.tags }}
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ FROM ubuntu:24.04 AS production
COPY --from=build /app/.pixi/envs/default /app/.pixi/envs/default
COPY --from=build /app/app.py /app
COPY --from=build /app/app_config.toml /app
COPY --from=build /app/version_info.json /app
COPY --from=build --chmod=0555 /entrypoint.sh /

WORKDIR /app
Expand Down
18 changes: 0 additions & 18 deletions conda_metadata_app/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import os
from collections.abc import Iterable
from enum import StrEnum
from subprocess import CalledProcessError, check_output
from typing import Literal, Self

from pydantic import (
Expand Down Expand Up @@ -428,22 +427,5 @@ def export_json_schema() -> None:
f.write("\n")


def app_version() -> str:
try:
return check_output(
[
"git",
"--no-pager",
"log",
"-1",
"--pretty=format:`%h (%cd)`",
"--date=format:%Y-%m-%d %H:%M:%S",
],
text=True,
).strip()
except CalledProcessError:
return ""


if __name__ == "__main__":
export_json_schema()
4 changes: 2 additions & 2 deletions conda_metadata_app/pages/main_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
MetadataRetrieval,
PackageDiscoveryChoice,
Secret,
app_version,
)
from conda_metadata_app.version_info import get_version_info
from conda_metadata_app.version_order import VersionOrder

if not os.environ.get("CACHE_DIR"):
Expand Down Expand Up @@ -71,7 +71,7 @@
initial_sidebar_state="expanded",
menu_items={
"about": f"""
**📦 conda-metadata-app `{app_version()}`**
**📦 conda-metadata-app `{get_version_info() or "(Version N/A)"}`**

Browse metadata from conda packages in conda-forge, bioconda and others.
"""
Expand Down
101 changes: 101 additions & 0 deletions conda_metadata_app/version_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""
This module provides a way to retrieve version information about conda-metadata-app.
"""

import datetime
import subprocess

from pydantic import BaseModel, Field
from streamlit.logger import get_logger

VERSION_INFO_FILE = "version_info.json"

LOGGER = get_logger(__name__)


class VersionInfo(BaseModel):
git_hash: str = Field(pattern=r"^[0-9a-f]{40}$")
timestamp: datetime.datetime

@property
def short_git_hash(self):
return self.git_hash[:7]

def timestamp_string(self):
return self.timestamp.strftime("%Y-%m-%d %H:%M:%S")

def __str__(self):
return f"{self.short_git_hash} ({self.timestamp_string()})"


def get_version_info_from_git() -> VersionInfo:
"""
Returns version information from the `.git` directory.
This requires you to have the `git` command line tool installed.

You should only use this function from a Streamlit Cloud deployment or
during the Docker build process, as neither git nor the `.git` directory
will be available in the final Docker image!

:raises FileNotFoundError: If git is not available.
:raises subprocess.CalledProcessError: If the git command fails.
"""
git_info = subprocess.check_output(
[
"git",
"--no-pager",
"log",
"-1",
"--pretty=format:%H-%cd",
"--date=unix",
],
text=True,
).strip()

git_hash, timestamp = git_info.split("-")

return VersionInfo(
git_hash=git_hash,
timestamp=datetime.datetime.fromtimestamp(int(timestamp), datetime.UTC),
)


def save_version_info_from_git() -> None:
"""
Saves the version information from git to version_info.json.
See the `get_version_info_from_git` function for more information.
"""
version_info = get_version_info_from_git()

with open(VERSION_INFO_FILE, "w") as f:
f.write(version_info.model_dump_json(indent=2))


def get_version_info() -> VersionInfo | None:
"""
Get the version information of the current app installation.
This works as follows:
1. Retrieve the version information from the `version_info.json` file (relevant for Docker image).
2. If the file does not exist, retrieve the version information from git (relevant for Streamlit Cloud).

:return: The version information or None if it could not be retrieved.
"""
try:
with open(VERSION_INFO_FILE) as f:
return VersionInfo.model_validate_json(f.read())
except FileNotFoundError:
pass

# fall back to retrieving the version information from git
try:
return get_version_info_from_git()
except (FileNotFoundError, subprocess.CalledProcessError):
LOGGER.warning(
"Unable to retrieve version information from git after finding that version.info.json is not available.",
exc_info=True,
)
return None


if __name__ == "__main__":
save_version_info_from_git()
2 changes: 2 additions & 0 deletions docker/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ pixi run -e default postinstall-production
echo "#!/bin/sh" > /entrypoint.sh
pixi shell-hook -e default -s bash >> /entrypoint.sh
echo 'exec "$@"' >> /entrypoint.sh

pixi run -e default save-version-info
1 change: 1 addition & 0 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ platforms = ["linux-64", "win-64", "osx-arm64", "osx-64", "linux-aarch64"]
dev = "python -m streamlit run --server.runOnSave=true app.py"
deploy = "python -m streamlit run --server.headless=true --global.developmentMode=false app.py"
schema = "python -m conda_metadata_app.app_config"
save-version-info = "python -m conda_metadata_app.version_info"
postinstall-production = "pip install --no-deps --disable-pip-version-check dist/conda_metadata_app-*.whl"


Expand Down