diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index a481249b6..017710df0 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -18,6 +18,7 @@ from django.utils.translation import gettext_lazy as _ from netbox.config import PARAMS as CONFIG_PARAMS from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW from netbox.plugins import PluginConfig +from utilities.release import load_release_data from utilities.string import trailing_slash @@ -25,7 +26,8 @@ from utilities.string import trailing_slash # Environment setup # -VERSION = '4.0.6-dev' +RELEASE = load_release_data() +VERSION = RELEASE.full_version # Retained for backward compatibility HOSTNAME = platform.node() # Set the base directory two levels up BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/netbox/release.yaml b/netbox/release.yaml new file mode 100644 index 000000000..83bddf615 --- /dev/null +++ b/netbox/release.yaml @@ -0,0 +1,2 @@ +version: "4.1.0" +designation: "dev" diff --git a/netbox/templates/base/layout.html b/netbox/templates/base/layout.html index 940f74346..397553446 100644 --- a/netbox/templates/base/layout.html +++ b/netbox/templates/base/layout.html @@ -188,12 +188,9 @@ Blocks: {# Footer text #} {# /Footer text #} diff --git a/netbox/utilities/release.py b/netbox/utilities/release.py new file mode 100644 index 000000000..dacec1010 --- /dev/null +++ b/netbox/utilities/release.py @@ -0,0 +1,57 @@ +import datetime +import os +import yaml +from dataclasses import dataclass +from typing import Union + +from django.core.exceptions import ImproperlyConfigured + +RELEASE_PATH = 'release.yaml' +LOCAL_RELEASE_PATH = 'local/release.yaml' + + +@dataclass +class ReleaseInfo: + version: str + edition: str = 'Community' + published: Union[datetime.date, None] = None + designation: Union[str, None] = None + + @property + def full_version(self): + if self.designation: + return f"{self.version}-{self.designation}" + return self.version + + @property + def name(self): + return f"NetBox {self.edition} v{self.full_version}" + + +def load_release_data(): + """ + Load any locally-defined release attributes and return a ReleaseInfo instance. + """ + base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + # Load canonical release attributes + with open(os.path.join(base_path, RELEASE_PATH), 'r') as release_file: + data = yaml.safe_load(release_file) + + # Overlay any local release date (if defined) + try: + with open(os.path.join(base_path, LOCAL_RELEASE_PATH), 'r') as release_file: + local_data = yaml.safe_load(release_file) + except FileNotFoundError: + local_data = {} + if type(local_data) is not dict: + raise ImproperlyConfigured( + f"{LOCAL_RELEASE_PATH}: Local release data must be defined as a dictionary." + ) + data.update(local_data) + + # Convert the published date to a date object + if 'published' in data: + data['published'] = datetime.date.fromisoformat(data['published']) + + return ReleaseInfo(**data)