Skip to content
Snippets Groups Projects
Commit 93d771ab authored by Corné Lukken's avatar Corné Lukken
Browse files

Merge branch 'L2SS-832' into 'master'

Resolve L2SS-832

Closes L2SS-832

See merge request !364
parents 445e419e 5fbb2a30
No related branches found
No related tags found
1 merge request!364Resolve L2SS-832
Showing
with 31 additions and 253 deletions
...@@ -567,8 +567,9 @@ wheel_packaging: ...@@ -567,8 +567,9 @@ wheel_packaging:
paths: paths:
- tangostationcontrol/dist/*.whl - tangostationcontrol/dist/*.whl
before_script: before_script:
- pip3 install build
- pip3 install -r tangostationcontrol/test-requirements.txt - pip3 install -r tangostationcontrol/test-requirements.txt
- pip3 install -r docker-compose/itango/lofar-requirements.txt - pip3 install -r docker-compose/itango/lofar-requirements.txt
script: script:
- cd tangostationcontrol - cd tangostationcontrol
- python setup.py bdist_wheel - python -m build
...@@ -32,10 +32,7 @@ if [[ $TANGOSTATIONCONTROL ]]; then ...@@ -32,10 +32,7 @@ if [[ $TANGOSTATIONCONTROL ]]; then
else else
# Install the package, exit 1 if it fails # Install the package, exit 1 if it fails
cd tangostationcontrol || exit 1 cd tangostationcontrol || exit 1
mkdir -p /tmp/tangostationcontrol pip install ./
python3 setup.py build --build-base /tmp/tangostationcontrol egg_info --egg-base /tmp/tangostationcontrol bdist_wheel --dist-dir /tmp/tangostationcontrol || exit 1
# shellcheck disable=SC2012
pip install "$(ls -Art /tmp/tangostationcontrol/*.whl | tail -n 1)"
fi fi
# Return to the stored the directory, this preserves the working_dir argument in # Return to the stored the directory, this preserves the working_dir argument in
......
GitPython >= 3.1.24 # BSD
ipython >=7.27.0,!=7.28.0 # BSD ipython >=7.27.0,!=7.28.0 # BSD
jupyter jupyter
ipykernel ipykernel
......
# Do not put tangostationcontrol dependencies here, only setup.py / __init__.py # Do not put tangostationcontrol dependencies here, only setup.py / __init__.py
GitPython >= 3.1.20 # BSD
include LICENSE
include README.md
include VERSION
0.1
\ No newline at end of file
[build-system]
requires = ['setuptools>=42', 'wheel']
build-backend = 'setuptools.build_meta'
...@@ -13,7 +13,5 @@ docker >= 5.0.3 # Apache 2 ...@@ -13,7 +13,5 @@ docker >= 5.0.3 # Apache 2
python-logstash-async >= 2.3.0 # MIT python-logstash-async >= 2.3.0 # MIT
python-casacore >= 3.3.1 # LGPLv3 python-casacore >= 3.3.1 # LGPLv3
etrs-itrs@git+https://github.com/brentjens/etrs-itrs # Apache 2 etrs-itrs@git+https://github.com/brentjens/etrs-itrs # Apache 2
# numpy must be manually added even though etrs-itrs requires it
numpy >= 1.21.0 # BSD
lofarantpos >= 0.5.0 # Apache 2 lofarantpos >= 0.5.0 # Apache 2
python-geohash >= 0.8.5 # Apache 2MIT python-geohash >= 0.8.5 # Apache 2 / MIT
[metadata] [metadata]
name = tangostationcontrol name = tangostationcontrol
version = attr: tangostationcontrol.__version__ version = file: VERSION
summary = LOFAR 2.0 Station Control summary = LOFAR 2.0 Station Control
description_file = description_file =
README.md README.md
...@@ -13,14 +13,12 @@ project_urls = ...@@ -13,14 +13,12 @@ project_urls =
license = Apache-2 license = Apache-2
classifier = classifier =
Environment :: Console Environment :: Console
Development Status :: 3 - Alpha
License :: Apache Software License License :: Apache Software License
Operating System :: POSIX :: Linux Operating System :: POSIX :: Linux
Programming Language :: Python Programming Language :: Python
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
[options] [options]
package_dir= package_dir=
...@@ -28,7 +26,8 @@ package_dir= ...@@ -28,7 +26,8 @@ package_dir=
packages=find: packages=find:
python_requires => 3.7 python_requires => 3.7
install_requires = install_requires =
GitPython>=3.1.20 importlib-metadata>=0.12;python_version<"3.8"
pip>=1.5
[options.packages.find] [options.packages.find]
where=. where=.
......
import setuptools
with open('requirements.txt') as f:
required = f.read().splitlines()
# Requires: setup.cfg
setuptools.setup(install_requires=required)
from tangostationcontrol.common.lofar_version import get_version try:
from importlib import metadata
except ImportError: # for Python<3.8
import importlib_metadata as metadata
__version__ = get_version() __version__ = metadata.version("tangostationcontrol")
def print_version(*args, **kwargs):
print(__version__)
...@@ -5,7 +5,7 @@ import traceback ...@@ -5,7 +5,7 @@ import traceback
import socket import socket
import time import time
from .lofar_version import get_version from tangostationcontrol import __version__ as version
class TangoLoggingHandler(logging.Handler): class TangoLoggingHandler(logging.Handler):
LEVEL_TO_DEVICE_STREAM = { LEVEL_TO_DEVICE_STREAM = {
...@@ -97,7 +97,7 @@ class LogAnnotator(logging.Formatter): ...@@ -97,7 +97,7 @@ class LogAnnotator(logging.Formatter):
record.lofar_id = f"tango - {record.tango_device}" record.lofar_id = f"tango - {record.tango_device}"
# annotate record with the current software version # annotate record with the current software version
record.software_version = get_version() record.software_version = version
# we just annotate, we don't filter # we just annotate, we don't filter
return True return True
......
import git
import os
import functools
import pkg_resources
import re
basepath = os.path.dirname(os.path.abspath(__file__))
def get_repo(starting_directory: str = basepath, limit = 10) -> git.Repo:
""" Try finding the repository by traversing up the tree.
By default, the repository containing this module is returned.
"""
directory = starting_directory
try:
return git.Repo(directory)
except git.InvalidGitRepositoryError:
pass
# We now have to traverse up the tree up until limit diretories
for _i in range(limit):
if directory == "/" or not os.path.exists(directory):
break
directory = os.path.abspath(directory + os.path.sep + "..")
try:
return git.Repo(directory)
except git.InvalidGitRepositoryError:
pass
# Could not find a repo within the limit so return None
return None
@functools.lru_cache(maxsize=None)
def get_version(repo: git.Repo = None) -> str:
""" Return a version string for the current commit.
There is a practical issue: the repository changes over time, f.e. switching branches with 'git checkout'. We want
to know the version that is running in memory, not the one that is on disk.
As a work-around, we cache the version information, in that it is at least consistent. It is up to the caller
to request the version early enough.
The version string is of the following pattern:
- ${MAJOR}.${MINOR}.${PATCH}[.${BRANCH}$.{COMMIT}][.dirty]
For releases only ${MAJOR}.${MINOR}.${PATCH} should be set. Versioning is
achieved by tagging commits using the `v${MAJOR}.${MINOR}.${PATCH}` pattern.
The leading `v` is none optional!
"""
if repo is None:
repo = get_repo()
# When we can't find a git repo anymore, we must be packaged. Extract the
# package version directly
if repo is None:
try:
return pkg_resources.require("tangostationcontrol")[0].version
except Exception:
pass
# Filter all tags so that they must match vMAJOR.MINOR.PATCH or
# vMAJOR.MINOR.PATCH.BRANCHCOMMIT
reg = re.compile(r'^v[0-9](\.[0-9]){2}(\.[a-z]*[0-9]*)?')
commit = repo.commit()
filtered_tags = [tag.name for tag in repo.tags if reg.search(tag.name)]
# Order tags from newest to oldest
tags = _order_tags(repo, filtered_tags)
# Find closest tag for commit
closest_tag = _find_closest_tag(commit, repo, tags)
if commit in tags:
# a tag = production ready
commit_str = "{}".format(tags[commit].name[1:])
elif repo.head.is_detached:
# no active branch
commit_str = "{}.{}".format(closest_tag.name[1:], commit)
else:
# HEAD of a branch
branch = repo.active_branch
commit_str = "{}.{}.{}".format(closest_tag.name[1:], branch, commit)
return "{}{}".format(commit_str, ".dirty" if repo.is_dirty() else "")
def _order_tags(repo, filtered_tags):
""" Helper function to order tags from newest to oldest """
return {tag.commit: tag for tag in reversed(repo.tags) if tag.name in filtered_tags}
def _find_closest_tag(commit, repo, tags):
""" Helper function to find closest tag for commit """
closest_tag = type('',(object,),{"name": 'v0.0.0'})()
for item in commit.iter_items(repo, commit):
if item.type == 'commit' and item in tags:
closest_tag = tags[item]
break
return closest_tag
# at least cache the current repo version immediately
try:
_ = get_version()
except Exception:
"B001 Do not use bare `except:`, it also catches unexpected events like"
"memory errors, interrupts, system exit"
pass
def main(args=None, **kwargs):
print(get_version())
...@@ -20,9 +20,9 @@ import numpy ...@@ -20,9 +20,9 @@ import numpy
import textwrap import textwrap
# Additional import # Additional import
from tangostationcontrol import __version__ as version
from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
from tangostationcontrol.common.lofar_logging import log_exceptions from tangostationcontrol.common.lofar_logging import log_exceptions
from tangostationcontrol.common.lofar_version import get_version
from tangostationcontrol.devices.device_decorators import only_in_states, fault_on_error from tangostationcontrol.devices.device_decorators import only_in_states, fault_on_error
from tangostationcontrol.toolkit.archiver import Archiver from tangostationcontrol.toolkit.archiver import Archiver
...@@ -75,7 +75,7 @@ class lofar_device(Device, metaclass=DeviceMeta): ...@@ -75,7 +75,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
# Attributes # Attributes
# ---------- # ----------
version_R = attribute(dtype=str, access=AttrWriteType.READ, fget=lambda self: get_version()) version_R = attribute(dtype=str, access=AttrWriteType.READ, fget=lambda self: version)
# list of translator property names to be set by set_translator_defaults # list of translator property names to be set by set_translator_defaults
TRANSLATOR_DEFAULT_SETTINGS = [] TRANSLATOR_DEFAULT_SETTINGS = []
......
...@@ -15,9 +15,9 @@ from tango import Except, DevFailed, DevState, AttrWriteType, DebugIt, DevicePro ...@@ -15,9 +15,9 @@ from tango import Except, DevFailed, DevState, AttrWriteType, DebugIt, DevicePro
from tango.server import Device, command, attribute from tango.server import Device, command, attribute
from tango import EventType from tango import EventType
from tangostationcontrol import __version__ as version
from tangostationcontrol.common.entrypoint import entry from tangostationcontrol.common.entrypoint import entry
from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
from tangostationcontrol.common.lofar_version import get_version
from tangostationcontrol.devices.device_decorators import only_when_on, fault_on_error from tangostationcontrol.devices.device_decorators import only_when_on, fault_on_error
from tangostationcontrol.devices.lofar_device import lofar_device from tangostationcontrol.devices.lofar_device import lofar_device
from tangostationcontrol.devices.observation import Observation from tangostationcontrol.devices.observation import Observation
...@@ -71,7 +71,7 @@ class ObservationControl(lofar_device): ...@@ -71,7 +71,7 @@ class ObservationControl(lofar_device):
- string version - string version
""" """
# Attributes # Attributes
version_R = attribute(dtype = str, access = AttrWriteType.READ, fget = lambda self: get_version()) version_R = attribute(dtype = str, access = AttrWriteType.READ, fget = lambda self: version)
running_observations_R = attribute(dtype = (numpy.int64, ), access = AttrWriteType.READ) running_observations_R = attribute(dtype = (numpy.int64, ), access = AttrWriteType.READ)
# Core functions # Core functions
......
# -*- coding: utf-8 -*-
#
# This file is part of the LOFAR 2.0 Station Software
#
#
#
# Distributed under the terms of the APACHE license.
# See LICENSE.txt for more info.
import git
from unittest import mock
from tangostationcontrol.common import lofar_version
from tangostationcontrol.test import base
class TestLofarVersion(base.TestCase):
def setUp(self):
super(TestLofarVersion, self).setUp()
# Clear the cache as this function of lofar_version uses LRU decorator
# This is a good demonstration of how unit tests in Python can have
# permanent effects, typically fixtures are needed to restore these.
lofar_version.get_version.cache_clear()
def test_get_version(self):
"""Test if attributes of get_repo are correctly used by get_version"""
with mock.patch.object(lofar_version, 'get_repo') as m_get_repo:
m_commit = mock.Mock()
m_commit.return_value.__str__ = mock.Mock(return_value="123456")
m_commit.return_value.iter_items.return_value = []
m_is_dirty = mock.Mock()
m_is_dirty.return_value = False
m_head = mock.Mock(is_detached=False)
m_get_repo.return_value = mock.Mock(
active_branch="main", commit=m_commit, tags=[],
is_dirty=m_is_dirty, head=m_head)
# No need for special string equal in Python
self.assertEqual("0.0.0.main.123456", lofar_version.get_version())
def test_get_version_tag(self):
"""Test if get_version determines production_ready for tagged commit"""
with mock.patch.object(lofar_version, 'get_repo') as m_get_repo:
m_commit = mock.Mock()
m_commit.return_value.__str__ = mock.Mock(return_value="123456")
m_commit.return_value.iter_items.return_value = []
m_is_dirty = mock.Mock()
m_is_dirty.return_value = False
m_head = mock.Mock(is_detached=False)
m_tag_commit = mock.Mock(type="commit")
m_tag_commit.__str__ = mock.Mock(return_value="123456")
m_tag = mock.Mock(commit=m_tag_commit)
m_tag.name = "v0.0.3"
m_tag.__str__ = mock.Mock(return_value= "v0.0.3")
m_commit.return_value = m_tag_commit
m_commit.return_value.iter_items.return_value = [m_tag_commit]
m_get_repo.return_value = mock.Mock(
active_branch="main", commit=m_commit,
tags=[m_tag], is_dirty=m_is_dirty, head=m_head)
self.assertEqual("0.0.3", lofar_version.get_version())
@mock.patch.object(lofar_version, 'get_repo')
def test_get_version_tag_dirty(self, m_get_repo):
"""Test if get_version determines dirty tagged commit"""
m_commit = mock.Mock()
m_commit.return_value.__str__ = mock.Mock(return_value="123456")
m_commit.return_value.iter_items.return_value = []
m_is_dirty = mock.Mock()
m_is_dirty.return_value = True
m_head = mock.Mock(is_detached=False)
m_get_repo.return_value = mock.Mock(
active_branch="main", commit=m_commit, tags=[],
is_dirty=m_is_dirty, head=m_head)
# No need for special string equal in Python
self.assertEqual("0.0.0.main.123456.dirty", lofar_version.get_version())
def test_catch_repo_error(self):
"""Test if invalid git directories will raise error"""
with mock.patch.object(lofar_version, 'get_repo') as m_get_repo:
# Configure lofar_version.get_repo to raise InvalidGitRepositoryError
m_get_repo.side_effect = git.InvalidGitRepositoryError
# Test that error is raised by get_version
self.assertRaises(
git.InvalidGitRepositoryError, lofar_version.get_version)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment