diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 679e890e..a80915b8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -5,6 +5,7 @@ on: - develop - release/** - hotfix/** + - feat/DEV-3737_Matrix_update tags: - '*' @@ -14,15 +15,19 @@ jobs: strategy: matrix: os: - - macos-12 - - macos-13 - macos-14 - - ubuntu-20.04 + - macos-15 + - macos-26 - ubuntu-22.04 - - windows-2019 + - ubuntu-24.04 - windows-2022 + - windows-2025 python: - - 3.8 + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" env: GDC_CLIENT_ZIP: 'gdc-client.zip' steps: @@ -34,17 +39,17 @@ jobs: uses: actions/setup-python@v3 with: python-version: ${{ matrix.python }} + - name: Install uv + uses: astral-sh/setup-uv@v9.0.0 - name: Run Tests - if: matrix.os != 'windows-latest' - run: | - pip install --upgrade pip - pip install tox - tox -e py + env: + NO_PROXY: "127.0.0.1,localhost" + UV_INDEX_URL: "https://pypi.org/simple" + run: uv run tox - name: Package run: | cd bin - pip install virtualenv - . ./package + uv run bash ./package echo "GDC_CLIENT_ZIP=$GDC_CLIENT_ZIP" >> $GITHUB_ENV shell: bash - uses: actions/upload-artifact@v4 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ce984552..2e5468d6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,6 @@ include: - templates/artifacts/python-library.yaml variables: - LANGUAGE_VERSION: python3.10 PYTHON_MULTIPROCESSING_START_METHOD: "fork" tox: diff --git a/bin/package b/bin/package index 079b7fa1..cc1f68e8 100755 --- a/bin/package +++ b/bin/package @@ -1,14 +1,6 @@ #!/usr/bin/env bash - set -euox pipefail -function cleanup() { - # get rid of the virtualenv - echo "Cleaning up" - deactivate - rm -rf "${VENV_NAME:?}/" build/ dist/ include/ local/ share/ gdc-client.spec -} - function compress() { # this way it's cross platform local zip_name=$1 @@ -24,76 +16,35 @@ with ZipFile('${zip_name}', 'w') as z: while getopts ":d" opt; do case $opt in - d) - DATE=$(date "+%m_%d_%Y") - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - ;; - esac + d) DATE=$(date "+%m_%d_%Y") ;; + \?) echo "Invalid option: -$OPTARG" >&2 ;; + esac done DATE=${DATE-} # if date is not passed in, default DATE variable to empty string -VENV_NAME="venv" BINARY_NAME="gdc-client" -VENV_PATH="$VENV_NAME/bin/activate" - -case $(uname -s) in - *NT*) - # for use in git bash with all the nice unix utilities - TARGET_ENVIRONMENT="Windows" - BINARY_NAME="gdc-client.exe" - - # this works in git bash - alias python="winpty python" - - # why does windows have to be so different? - VENV_PATH="$VENV_NAME/Scripts/activate" - # Presumably Python3 is the only `python` in the Windows %PATH% variable - python -m virtualenv "$VENV_NAME" - source "$VENV_PATH" - pip install pywin32 - ;; - *Linux*) - TARGET_ENVIRONMENT="Ubuntu" - python -m virtualenv "$VENV_NAME" --python=python3 - source "$VENV_PATH" - ;; - *Darwin*) - TARGET_ENVIRONMENT="OSX" - python -m virtualenv "$VENV_NAME" --python=python3 - source "$VENV_PATH" - ;; +case "$(uname -s)" in + *NT*) TARGET_ENVIRONMENT="Windows"; BINARY_NAME="gdc-client.exe" ;; + *Linux*) TARGET_ENVIRONMENT="Ubuntu" ;; + *Darwin*) TARGET_ENVIRONMENT="OSX" ;; + *) echo "Unsupported OS"; exit 1 ;; esac # setup.py is in previous dir cd .. -python -m pip install --upgrade pip -python -m pip install --no-deps -r requirements.txt -python -m pip install --no-deps . +uv sync --locked --no-dev --no-editable -# go back go the ./gdc_client/bin dir cd bin echo "Building for ${TARGET_ENVIRONMENT}..." - -# Make sure the correct version of pyinstaller and setuptools are installed -pip install -U PyInstaller - -# Ran into ModuleNotFoundError: No module named 'pkg_resources.py2_warn' with higher versions of setuptools -pip install --upgrade setuptools - # Get version -VERSION=$(python -c " +VERSION=$(uv run python -c " import gdc_client.version print(gdc_client.version.__version__)") -echo "Creating ${TARGET_ENVIRONMENT} package for version ${VERSION}..." - -# Create binary -pyinstaller \ +uv run --with pyinstaller pyinstaller \ --clean \ --additional-hooks-dir=. \ --noconfirm \ @@ -118,7 +69,3 @@ ZIP_NAME="$PRE_ZIP_NAME.zip" echo "The output zip file will be called ${ZIP_NAME}" compress "$ZIP_NAME" "$BINARY_NAME" mv "$ZIP_NAME" .. -cd .. - -cleanup -export GDC_CLIENT_ZIP="$PRE_ZIP_NAME" diff --git a/pyproject.toml b/pyproject.toml index 7cf7e209..705f5a8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=64", "setuptools_scm>=8"] +requires = ["setuptools>=80", "setuptools_scm>=8"] build-backend = "setuptools.build_meta" [project] diff --git a/src/gdc_client/version.py b/src/gdc_client/version.py index 894cfbac..5aba7afb 100644 --- a/src/gdc_client/version.py +++ b/src/gdc_client/version.py @@ -1,3 +1,3 @@ -from importlib_metadata import version +from importlib.metadata import version __version__ = version("gdc_client") diff --git a/tests/conftest.py b/tests/conftest.py index 64534f3f..c09e6be9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,10 +1,12 @@ import hashlib import hmac +import multiprocessing import tarfile import time +import urllib.error +import urllib.request from collections.abc import Iterable, Mapping from io import BytesIO -from multiprocessing import Process from unittest.mock import patch import boto3 @@ -141,11 +143,32 @@ def run_mock_server(): @pytest.fixture(scope="class") def setup_mock_server() -> None: - server = Process(target=run_mock_server) + # MacOS does things differently, so get everyone acting the same way + try: + ctx = multiprocessing.get_context("fork") + server = ctx.Process(target=run_mock_server) + except ValueError: + server = multiprocessing.Process(target=run_mock_server) + server.start() - time.sleep(5) # starting with py38, takes longer for process to start on macOS + + # Since py38, a sleep is needed for MacOS. 10 is no longer enough as of py310 + # Instead of time.sleep(30), this loop could exit faster. + for _ in range(60): + try: + with urllib.request.urlopen("http://127.0.0.1:5000", timeout=1): + break + # listen for any response, and then stop waiting + except urllib.error.HTTPError: + break + except Exception: + time.sleep(0.5) + else: + raise RuntimeError("Mock server failed to start on 127.0.0.1:5000 in 30 secs.") + yield server.terminate() + server.join() @pytest.fixture