diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml new file mode 100644 index 0000000..ce90d74 --- /dev/null +++ b/.github/workflows/unittests.yaml @@ -0,0 +1,74 @@ +name: Pytest + +on: + push: + branches: + - master + pull_request: {} + +jobs: + test: + name: Unit Tests + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-22.04, windows-latest, macos-latest] + python-version: ["3.8", "3.9", "3.10", "3.11"] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + cache: pip + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-cov + pip install -r requirements.txt + + - name: Test + run: | + pytest + + coverage: + name: Coverage Summary + runs-on: ubuntu-22.04 + permissions: + pull-requests: write + contents: read + + if: github.event_name == 'pull_request' + strategy: + fail-fast: false + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.11" + cache: pip + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-cov + pip install -r requirements.txt + + - name: Run Coverage + run: | + pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=semver | tee pytest-coverage.txt + + - name: Comment Result Summary + uses: MishaKav/pytest-coverage-comment@main + with: + pytest-coverage-path: ./pytest-coverage.txt + junitxml-path: ./pytest.xml diff --git a/Dockerfile b/Dockerfile index af9c6be..190f287 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,29 +1,33 @@ -FROM centos/python-36-centos7 - -USER root +# ======= # +# Builder # +# ======= # +FROM python:3.11-slim as builder +COPY / /semver +RUN pip wheel --no-cache-dir --wheel-dir /wheels /semver -#Perform updates -RUN pip install --upgrade pip -RUN yum update -y -RUN yum -y remove git -RUN yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm -RUN yum -y install git +# ======== # +# Finalize # +# ======== # +FROM python:3.11-slim -#Setup semver -ADD / /semver -WORKDIR /semver -RUN python setup.py sdist -RUN pip install dist/semver-*.tar.gz +# Update and install git +RUN apt-get update && apt-get install -y git + +# Create user +RUN mkdir /semver && \ + groupadd -g 10001 semver && \ + useradd -u 10000 -g semver -d /semver semver \ + && chown -R semver:semver /semver # Prep workspace -RUN mkdir /workspace -WORKDIR /workspace +RUN mkdir /workspace && \ + chown -R semver:semver /workspace VOLUME /workspace -#Permissions -RUN useradd -d /semverUser semverUser -RUN chown -R semverUser:semverUser /workspace +# Setup semver +COPY --from=builder /wheels /semver/wheels +RUN pip install --no-cache /semver/wheels/* -CMD [ "semver" ] - -USER semverUser +USER semver:semver +WORKDIR /workspace +ENTRYPOINT [ "semver" ] diff --git a/semver/__init__.py b/semver/__init__.py index bda8f5c..ecfeaab 100644 --- a/semver/__init__.py +++ b/semver/__init__.py @@ -27,19 +27,19 @@ def main(): """Main entry point for the application""" parser = argparse.ArgumentParser(description="Bump Semantic Version.") parser.add_argument( - "-n", "--no-push", help="Do not try to push", action="store_false", dest="push" + "-n", "--no-push", help="do not try to push", action="store_false", dest="push" ) parser.add_argument( "-g", "--global-user", - help="Set git user at a global level, helps in jenkins", + help="set git user at a global level", action="store_true", dest="global_user", ) parser.add_argument( "-D", "--debug", - help="Sets logging level to DEBUG", + help="sets logging level to DEBUG", action="store_true", dest="debug", default=False, diff --git a/semver/get_version.py b/semver/get_version.py index 38e9921..2533a11 100644 --- a/semver/get_version.py +++ b/semver/get_version.py @@ -11,14 +11,14 @@ def main(): parser.add_argument( "-d", "--dot", - help="Switch out / for . to be used in docker tag", + help="switch out / for . to be used in docker tag", action="store_true", dest="dot", ) parser.add_argument( "-D", "--debug", - help="Sets logging level to DEBUG", + help="sets logging level to DEBUG", action="store_true", dest="debug", default=False, @@ -26,12 +26,12 @@ def main(): parser.add_argument( "-f", "--format", - help="Format for pre-release version syntax", + help="format for pre-release version syntax", choices=["npm", "maven", "docker"], default=None, ) parser.add_argument( - "-b", "--build-number", help="Build number, used in pre-releases", default=0 + "-b", "--build-number", help="build number, used in pre-releases", default=0 ) args = parser.parse_args() diff --git a/semver/scm/git.py b/semver/scm/git.py index 4b9a620..cc1255a 100644 --- a/semver/scm/git.py +++ b/semver/scm/git.py @@ -1,7 +1,7 @@ import re import subprocess from typing import Union, List -from functools import cache +from functools import lru_cache import toml @@ -29,7 +29,7 @@ class Git(SCM): def _run_command( self, *args: str, throwExceptions: bool = True - ) -> subprocess.CompletedProcess[str]: + ) -> subprocess.CompletedProcess: return subprocess.run( args, capture_output=True, @@ -82,13 +82,17 @@ class Git(SCM): f"Error getting latest tagged git version: {str(e.stderr).rstrip()}" ) - if len(tagged_versions) > 0 and tagged_versions[-1] != "": + if ( + tagged_versions is not None + and len(tagged_versions) > 0 + and tagged_versions[-1] != "" + ): version = tagged_versions[-1] logger.debug(f"Tag Version: {version}") return version - @cache + @lru_cache(maxsize=None) def get_branch(self) -> str: """ Get the main branch @@ -97,7 +101,7 @@ class Git(SCM): proc = self._run_command(self.git_bin, "rev-parse", "--abbrev-ref", "HEAD") return proc.stdout.rstrip() - @cache + @lru_cache(maxsize=None) def get_merge_branch(self) -> Union[str, None]: """ Get the branches involved in the merge diff --git a/semver/scm/perforce.py b/semver/scm/perforce.py deleted file mode 100644 index a82a348..0000000 --- a/semver/scm/perforce.py +++ /dev/null @@ -1,49 +0,0 @@ -import subprocess -from typing import Union, List - -import toml - -from semver.scm import SCM -from semver.logger import logger - - -class Perforce(SCM): - def __init__(self) -> None: - super().__init__() - - def get_tag_version(self) -> str: - """ - Get the latest tagged version from Perforce labels - :return: The latest tagged version - """ - config: dict = toml.load("./.bumpversion.cfg") - - tag_expression: str = config["bumpversion"]["tag_name"].replace( - "{new_version}", "[0-9]*.[0-9]*.[0-9]*" - ) - - logger.debug("Tag expression: " + str(tag_expression)) - - # Default version is `0.0.0` or what is found in - version = self.get_file_version(config) - - # If a version is found in Perforce labels, use that the latest labeled version - labeled_versions: Union[List[str], None] = None - try: - proc = subprocess.run( - ["p4", "labels", "-e", tag_expression, "-m1"], - capture_output=True, - text=True, - check=True, - ) - labeled_versions = proc.stdout.rstrip().split("\n") - except subprocess.CalledProcessError as e: - raise RuntimeError( - f"Error getting latest labeled Perforce version: {str(e.stderr).rstrip()}" - ) - - if len(labeled_versions) > 0 and labeled_versions[-1] != "": - version = labeled_versions[-1] - - logger.debug("Label Version: " + str(version)) - return version diff --git a/semver/tests/test_semver.py b/semver/tests/test_semver.py index 554b85d..0739714 100644 --- a/semver/tests/test_semver.py +++ b/semver/tests/test_semver.py @@ -67,10 +67,8 @@ class TestSemVer(unittest.TestCase): @mock.patch("toml.load") @mock.patch("pathlib.Path.is_file") @mock.patch("builtins.open", mock.mock_open()) - @mock.patch("semver.logger.warning") def test_update_file_version( self, - mock_logger: mock.Mock, mock_path_is_file: mock.Mock, mock_toml_load: mock.Mock, ): @@ -83,11 +81,9 @@ class TestSemVer(unittest.TestCase): } mock_path_is_file.return_value = True self.semver._update_file_version("1.0.1", "1.0.0") - mock_logger.assert_not_called() mock_path_is_file.return_value = False self.semver._update_file_version("1.0.1", "1.0.0") - mock_logger.assert_called_once() @mock.patch("semver.semver.SemVer._version_repo", mock.MagicMock()) def test_run_ok(self): diff --git a/semver/utils.py b/semver/utils.py index 82955b8..c155470 100644 --- a/semver/utils.py +++ b/semver/utils.py @@ -1,6 +1,6 @@ from typing import List from pathlib import Path -from functools import cache +from functools import lru_cache import configparser import toml @@ -8,7 +8,7 @@ import toml from semver.exceptions import SemverException -@cache +@lru_cache(maxsize=None) def get_settings() -> dict: """ Get the settings from the config file diff --git a/setup.cfg b/setup.cfg index d1e0c79..f41ff02 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,7 +24,9 @@ classifiers = [options] include_package_data = True packages = find: -python_requires = >=3.7, <4 +python_requires = >=3.8, <4 +install_requires = + toml [options.packages.find] exclude =