diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ac698f8..4ed2d90 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,16 +1,30 @@ # New Features - + +* tbd * tbd # Changes +* tbd * tbd # Bug Fixes +* tbd * tbd ----------- -# Related PRs: +# Documentation * tbd +* tbd + +# Unit Tests + +* tbd +* tbd + +---------- +# Related Issues and Pull-Requests + +* tbd +* tbd diff --git a/.github/workflows/ApplicationTesting.yml b/.github/workflows/ApplicationTesting.yml index c327cb9..3f91d6a 100644 --- a/.github/workflows/ApplicationTesting.yml +++ b/.github/workflows/ApplicationTesting.yml @@ -124,26 +124,34 @@ jobs: requirements = "${{ inputs.requirements }}" if requirements.startswith("-r"): requirementsFile = Path(requirements[2:].lstrip()) - dependencies = loadRequirementsFile(requirementsFile) + try: + dependencies = loadRequirementsFile(requirementsFile) + except FileNotFoundError as ex: + print(f"::error title=FileNotFoundError::{ex}") + exit(1) else: dependencies = [req.strip() for req in requirements.split(" ")] packages = { - "coverage": "python-coverage:p", - "igraph": "igraph:p", - "jinja2": "python-markupsafe:p", - "lxml": "python-lxml:p", - "numpy": "python-numpy:p", - "markupsafe": "python-markupsafe:p", - "pip": "python-pip:p", - "ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", - "sphinx": "python-markupsafe:p", - "tomli": "python-tomli:p", - "wheel": "python-wheel:p", + "coverage": "python-coverage:p", + "docstr_coverage": "python-pyyaml:p", + "igraph": "igraph:p", + "jinja2": "python-markupsafe:p", + "lxml": "python-lxml:p", + "numpy": "python-numpy:p", + "markupsafe": "python-markupsafe:p", + "pip": "python-pip:p", + "pyyaml": "python-pyyaml:p", + "ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", + "sphinx": "python-markupsafe:p", + "tomli": "python-tomli:p", + "wheel": "python-wheel:p", + "pyEDAA.ProjectModel": "python-ruamel-yaml:p python-ruamel.yaml.clib:p python-lxml:p", + "pyEDAA.Reports": "python-ruamel-yaml:p python-ruamel.yaml.clib:p python-lxml:p", } subPackages = { "pytooling": { - "yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", + "yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", } } @@ -215,7 +223,7 @@ jobs: ls -l install python -m pip install --disable-pip-version-check -U install/*.whl - - name: ☑ Run application tests (Ubuntu/macOS) + - name: ✅ Run application tests (Ubuntu/macOS) if: matrix.system != 'windows' run: | export ENVIRONMENT_NAME="${{ matrix.envname }}" @@ -230,7 +238,7 @@ jobs: python -m pytest -raP $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.apptest_directory }} fi - - name: ☑ Run application tests (Windows) + - name: ✅ Run application tests (Windows) if: matrix.system == 'windows' run: | $env:ENVIRONMENT_NAME = "${{ matrix.envname }}" diff --git a/.github/workflows/ArtifactCleanUp.yml b/.github/workflows/ArtifactCleanUp.yml index abfb8d9..97929fb 100644 --- a/.github/workflows/ArtifactCleanUp.yml +++ b/.github/workflows/ArtifactCleanUp.yml @@ -38,7 +38,7 @@ on: jobs: ArtifactCleanUp: name: 🗑️ Artifact Cleanup - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: 🗑️ Delete package Artifacts diff --git a/.github/workflows/BuildTheDocs.yml b/.github/workflows/BuildTheDocs.yml index 44b13ea..a8d72c1 100644 --- a/.github/workflows/BuildTheDocs.yml +++ b/.github/workflows/BuildTheDocs.yml @@ -34,7 +34,7 @@ on: jobs: BuildTheDocs: name: 📓 Run BuildTheDocs - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository diff --git a/.github/workflows/CheckDocumentation.yml b/.github/workflows/CheckDocumentation.yml index c092b5c..e88a6bd 100644 --- a/.github/workflows/CheckDocumentation.yml +++ b/.github/workflows/CheckDocumentation.yml @@ -33,16 +33,16 @@ on: description: 'Source code directory to check.' required: true type: string -# fail_below: -# description: 'Minimum required documentation coverage level' -# required: false -# default: 75 -# type: string + fail_under: + description: 'Minimum required documentation coverage level' + required: false + default: 80 + type: string jobs: DocCoverage: name: 👀 Check documentation coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository uses: actions/checkout@v4 @@ -59,9 +59,9 @@ jobs: - name: Run 'interrogate' Documentation Coverage Check continue-on-error: true run: | - interrogate -c pyproject.toml + interrogate -c pyproject.toml --fail-under=${{ inputs.fail_under }} && echo "::error title=interrogate::Insufficient documentation quality (goal: ${{ inputs.fail_under }})" - name: Run 'docstr_coverage' Documentation Coverage Check continue-on-error: true run: | - docstr_coverage -v ${{ inputs.directory }} + docstr-coverage -v 2 --fail-under=${{ inputs.fail_under }} ${{ inputs.directory }} && echo "::error title=docstr-coverage::Insufficient documentation quality (goal: ${{ inputs.fail_under }})" diff --git a/.github/workflows/CoverageCollection.yml b/.github/workflows/CoverageCollection.yml index 2922e25..4f8b019 100644 --- a/.github/workflows/CoverageCollection.yml +++ b/.github/workflows/CoverageCollection.yml @@ -63,7 +63,7 @@ jobs: Coverage: name: 📈 Collect Coverage Data using Python ${{ inputs.python_version }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository @@ -102,7 +102,9 @@ jobs: htmlDirectory = pyProjectSettings["tool"]["coverage"]["html"]["directory"] xmlFile = pyProjectSettings["tool"]["coverage"]["xml"]["output"] else: - print(f"File '{pyProjectFile}' not found and no ' .coveragerc' file specified.") + print(f"File '{pyProjectFile}' not found.") + print(f"::error title=FileNotFoundError::File '{pyProjectFile}' not found.") + exit(1) # Read output paths from '.coveragerc' file elif len(coverageRC) > 0: @@ -115,6 +117,8 @@ jobs: xmlFile = coverageRCSettings["xml"]["output"] else: print(f"File '{coverageRCFile}' not found.") + print(f"::error title=FileNotFoundError::File '{coverageRCFile}' not found.") + exit(1) # Write jobs to special file github_output = Path(getenv("GITHUB_OUTPUT")) diff --git a/.github/workflows/IntermediateCleanUp.yml b/.github/workflows/IntermediateCleanUp.yml index 927a3d3..d087ea6 100644 --- a/.github/workflows/IntermediateCleanUp.yml +++ b/.github/workflows/IntermediateCleanUp.yml @@ -36,7 +36,7 @@ on: jobs: IntermediateCleanUp: name: 🗑️ Intermediate Artifact Cleanup - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: 🗑️ Delete SQLite coverage artifacts from matrix jobs uses: geekyeggo/delete-artifact@v5 diff --git a/.github/workflows/LaTeXDocumentation.yml b/.github/workflows/LaTeXDocumentation.yml index 0c4d375..675ae04 100644 --- a/.github/workflows/LaTeXDocumentation.yml +++ b/.github/workflows/LaTeXDocumentation.yml @@ -42,7 +42,7 @@ on: jobs: PDFDocumentation: name: 📓 Converting LaTeX Documentation to PDF - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: 📥 Download artifacts '${{ inputs.latex_artifact }}' from 'SphinxDocumentation' job uses: actions/download-artifact@v4 diff --git a/.github/workflows/Package.yml b/.github/workflows/Package.yml index 5378fbc..b18ad87 100644 --- a/.github/workflows/Package.yml +++ b/.github/workflows/Package.yml @@ -44,7 +44,7 @@ jobs: Package: name: 📦 Package in Source and Wheel Format - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository diff --git a/.github/workflows/Parameters.yml b/.github/workflows/Parameters.yml index 620b706..dd2f549 100644 --- a/.github/workflows/Parameters.yml +++ b/.github/workflows/Parameters.yml @@ -42,7 +42,7 @@ on: system_list: description: 'Space separated list of systems to run tests on.' required: false - default: 'ubuntu windows macos mingw64 ucrt64' + default: 'ubuntu windows macos-arm mingw64 ucrt64' type: string include_list: description: 'Space separated list of system:python items to be included into the list of test.' @@ -59,6 +59,26 @@ on: required: false default: '' type: string + ubuntu_image: + description: 'The used GitHub Action image for Ubuntu based jobs.' + required: false + default: 'ubuntu-24.04' + type: string + windows_image: + description: 'The used GitHub Action image for Windows based jobs.' + required: false + default: 'windows-latest' + type: string + macos_intel_image: + description: 'The used GitHub Action image for macOS (Intel x86-64) based jobs.' + required: false + default: 'macos-latest-large' + type: string + macos_arm_image: + description: 'The used GitHub Action image for macOS (ARM arm64) based jobs.' + required: false + default: 'macos-latest' + type: string outputs: python_version: @@ -76,7 +96,7 @@ on: jobs: Parameters: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: python_version: ${{ steps.params.outputs.python_version }} python_jobs: ${{ steps.params.outputs.python_jobs }} @@ -91,8 +111,8 @@ jobs: from json import dumps as json_dumps from os import getenv from pathlib import Path - from pprint import pprint from textwrap import dedent + from typing import Iterable name = "${{ inputs.name }}".strip() python_version = "${{ inputs.python_version }}".strip() @@ -138,7 +158,7 @@ jobs: if currentAlphaVersion in versions: print(f"::notice title=Experimental::Python {currentAlphaVersion} ({currentAlphaRelease}) is a pre-release.") for disable in disabled: - print(f"::warning title=Disabled Python Job::System '{disable}' temporary disabled.") + print(f"::warning title=Disabled Python Job::System '{disable}' temporarily disabled.") # see https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json data = { @@ -158,9 +178,10 @@ jobs: }, # Runner systems (runner images) supported by GitHub Actions "sys": { - "ubuntu": { "icon": "🐧", "runs-on": "ubuntu-latest", "shell": "bash", "name": "Linux (x86-64)", "minPy": (3, 7)}, - "windows": { "icon": "🪟", "runs-on": "windows-latest", "shell": "pwsh", "name": "Windows (x86-64)", "minPy": (3, 7)}, - "macos": { "icon": "🍎", "runs-on": "macos-latest", "shell": "bash", "name": "MacOS (x86-64)", "minPy": (3, 10)}, + "ubuntu": { "icon": "🐧", "runs-on": "${{ inputs.ubuntu_image }}", "shell": "bash", "name": "Linux (x86-64)" }, + "windows": { "icon": "🪟", "runs-on": "${{ inputs.windows_image }}", "shell": "pwsh", "name": "Windows (x86-64)" }, + "macos": { "icon": "🍎", "runs-on": "${{ inputs.macos_intel_image }}", "shell": "bash", "name": "macOS (x86-64)" }, + "macos-arm": { "icon": "🍏", "runs-on": "${{ inputs.macos_arm_image }}", "shell": "bash", "name": "macOS (arm64)" }, }, # Runtimes provided by MSYS2 "runtime": { @@ -183,9 +204,23 @@ jobs: for disable in disabled: print(f"- {disable}") - def toVersion(value): - major, minor = value.split(".") - return int(major[-1]), int(minor) + def match(combination: str, pattern: str) -> bool: + system, version = combination.split(":") + sys, ver = pattern.split(":") + + if sys == "*": + return (ver == "*") or (version == ver) + elif system == sys: + return (ver == "*") or (version == ver) + else: + return False + + def notIn(combination: str, patterns: Iterable[str]) -> bool: + for pattern in patterns: + if match(combination, pattern): + return False + + return True combinations = [ (system, version) @@ -193,22 +228,20 @@ jobs: if system in data["sys"] for version in versions if version in data["python"] - and toVersion(version) >= data["sys"][system]["minPy"] - and f"{system}:{version}" not in excludes - and f"{system}:{version}" not in disabled + and notIn(f"{system}:{version}", excludes) + and notIn(f"{system}:{version}", disabled) ] + [ (system, currentMSYS2Version) for system in systems if system in data["runtime"] - and f"{system}:{currentMSYS2Version}" not in excludes - and f"{system}:{currentMSYS2Version}" not in disabled + and notIn(f"{system}:{currentMSYS2Version}", excludes) + and notIn(f"{system}:{currentMSYS2Version}", disabled) ] + [ (system, version) for system, version in includes if system in data["sys"] and version in data["python"] - and toVersion(version) >= data["sys"][system]["minPy"] - and f"{system}:{version}" not in disabled + and notIn(f"{system}:{version}", disabled) ] print(f"Combinations ({len(combinations)}):") for system, version in combinations: diff --git a/.github/workflows/PublishCoverageResults.yml b/.github/workflows/PublishCoverageResults.yml index b45c1de..395a120 100644 --- a/.github/workflows/PublishCoverageResults.yml +++ b/.github/workflows/PublishCoverageResults.yml @@ -57,7 +57,7 @@ on: jobs: PublishCoverageResults: name: 📊 Publish Code Coverage Results - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: always() steps: @@ -71,7 +71,7 @@ jobs: - name: 🔧 Install coverage and tomli run: | - python -m pip install --disable-pip-version-check -U coverage[toml] tomli + python -m pip install -U --disable-pip-version-check --break-system-packages coverage[toml] tomli - name: 🔁 Extract configurations from pyproject.toml id: getVariables @@ -102,7 +102,9 @@ jobs: xmlFile = Path(pyProjectSettings["tool"]["coverage"]["xml"]["output"]) jsonFile = Path(pyProjectSettings["tool"]["coverage"]["json"]["output"]) else: - print(f"File '{pyProjectFile}' not found and no '.coveragerc' file specified.") + print(f"File '{pyProjectFile}' not found.") + print(f"::error title=FileNotFoundError::File '{pyProjectFile}' not found.") + exit(1) # Read output paths from '.coveragerc' file elif len(coverageRC) > 0: @@ -116,6 +118,8 @@ jobs: jsonFile = Path(coverageRCSettings["json"]["output"]) else: print(f"File '{coverageRCFile}' not found.") + print(f"::error title=FileNotFoundError::File '{coverageRCFile}' not found.") + exit(1) # Write jobs to special file github_output = Path(getenv("GITHUB_OUTPUT")) @@ -131,8 +135,10 @@ jobs: - name: Rename .coverage files and collect them all to coverage/ run: | + ls -lAh artifacts/ + ls -lAh artifacts/*/.coverage mkdir -p coverage - find . -type f -path "*artifacts*SQLite*.coverage" -exec sh -c 'cp -v $0 "coverage/$(basename $0).$(basename $(dirname $0))"' {} ';' + find artifacts/ -type f -path "*SQLite*.coverage" -exec sh -c 'cp -v $0 "coverage/$(basename $0).$(basename $(dirname $0))"' {} ';' tree -a coverage - name: Combine SQLite files (using Coverage.py) diff --git a/.github/workflows/PublishOnPyPI.yml b/.github/workflows/PublishOnPyPI.yml index 890595c..f108670 100644 --- a/.github/workflows/PublishOnPyPI.yml +++ b/.github/workflows/PublishOnPyPI.yml @@ -48,7 +48,7 @@ jobs: PublishOnPyPI: name: 🚀 Publish to PyPI - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: 📥 Download artifacts '${{ inputs.artifact }}' from 'Package' job diff --git a/.github/workflows/PublishTestResults.yml b/.github/workflows/PublishTestResults.yml index fd9391a..dcfbd9e 100644 --- a/.github/workflows/PublishTestResults.yml +++ b/.github/workflows/PublishTestResults.yml @@ -30,11 +30,21 @@ on: required: false default: '' type: string + additional_merge_args: + description: 'Additional merging arguments.' + required: false + default: '"--pytest=rewrite-dunder-init;reduce-depth:pytest.tests.unit"' + type: string + report_title: + description: 'Title of the summary report in the pipeline''s sidebar' + required: false + default: 'Unit Test Results' + type: string jobs: PublishTestResults: name: 📊 Publish Test Results - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: always() steps: @@ -46,37 +56,28 @@ jobs: with: path: artifacts - - name: 🔧 Install junitparser + - name: 🔧 Install pyEDAA.Reports (JUunit Parser and Merger) run: | - python -m pip install --disable-pip-version-check -U junitparser + python -m pip install --disable-pip-version-check --break-system-packages -U pyEDAA.Reports - name: Move JUnit files and collect them all to junit/ run: | mkdir -p junit - find . -type f -path "*artifacts*UnitTestReportSummary*.xml" -exec sh -c 'cp -v $0 "junit/$(basename $(dirname $0)).$(basename $0)"' {} ';' + ls -lAh artifacts/*/*.xml + find artifacts/ -type f -path "*TestReportSummary*.xml" -exec sh -c 'cp -v $0 "junit/$(basename $(dirname $0)).$(basename $0)"' {} ';' tree -a junit - name: 🔁 Merge JUnit Unit Test Summaries - shell: python run: | - from pathlib import Path - from junitparser import JUnitXml - - junitDirectory = Path("junit") - junitXml = None - for file in junitDirectory.iterdir(): - if junitXml is None: - junitXml = JUnitXml.fromfile(file) - else: - junitXml += JUnitXml.fromfile(file) - - junitXml.write(junitDirectory / "merged.xml") + pyedaa-reports -v unittest "--merge=pytest-junit:junit/*.xml" ${{ inputs.additional_merge_args }} "--output=ant-junit:Unittesting.xml" + echo "cat Unittesting.xml" + cat Unittesting.xml - name: 📊 Publish Unit Test Results uses: dorny/test-reporter@v1 with: - name: Unit Test Results - path: junit/merged.xml + name: ${{ inputs.report_title }} + path: Unittesting.xml reporter: java-junit - name: 📤 Upload merged 'JUnit Test Summary' artifact @@ -84,6 +85,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ inputs.merged_junit_artifact }} - path: junit/merged.xml + path: Unittesting.xml if-no-files-found: error retention-days: 1 diff --git a/.github/workflows/PublishToGitHubPages.yml b/.github/workflows/PublishToGitHubPages.yml index 351eb02..325512b 100644 --- a/.github/workflows/PublishToGitHubPages.yml +++ b/.github/workflows/PublishToGitHubPages.yml @@ -44,7 +44,7 @@ jobs: PublishToGitHubPages: name: 📚 Publish to GH-Pages - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index cc3d493..764eee7 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -29,7 +29,7 @@ jobs: Release: name: 📝 Create 'Release Page' on GitHub - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: 🔁 Extract Git tag from GITHUB_REF @@ -55,12 +55,34 @@ jobs: **Automated Release created on: ${{ steps.getVariables.outputs.datetime }}** # New Features + + * tbd * tbd # Changes + + * tbd * tbd # Bug Fixes + * tbd - draft: false + * tbd + + # Documentation + + * tbd + * tbd + + # Unit Tests + + * tbd + * tbd + + ---------- + # Related Issues and Pull-Requests + + * tbd + * tbd + draft: true prerelease: false diff --git a/.github/workflows/SphinxDocumentation.yml b/.github/workflows/SphinxDocumentation.yml index 34f9d48..6fe793b 100644 --- a/.github/workflows/SphinxDocumentation.yml +++ b/.github/workflows/SphinxDocumentation.yml @@ -73,7 +73,7 @@ on: jobs: Sphinx: name: 📓 Documentation generation using Sphinx and Python ${{ inputs.python_version }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository @@ -121,7 +121,9 @@ jobs: xmlFile = Path(pyProjectSettings["tool"]["coverage"]["xml"]["output"]) jsonFile = Path(pyProjectSettings["tool"]["coverage"]["json"]["output"]) else: - print(f"File '{pyProjectFile}' not found and no '.coveragerc' file specified.") + print(f"File '{pyProjectFile}' not found.") + print(f"::error title=FileNotFoundError::File '{pyProjectFile}' not found.") + exit(1) # Read output paths from '.coveragerc' file elif len(coverageRC) > 0: @@ -135,6 +137,8 @@ jobs: jsonFile = Path(coverageRCSettings["json"]["output"]) else: print(f"File '{coverageRCFile}' not found.") + print(f"::error title=FileNotFoundError::File '{coverageRCFile}' not found.") + exit(1) # Write jobs to special file github_output = Path(getenv("GITHUB_OUTPUT")) diff --git a/.github/workflows/StaticTypeCheck.yml b/.github/workflows/StaticTypeCheck.yml index eef16f3..c37d64f 100644 --- a/.github/workflows/StaticTypeCheck.yml +++ b/.github/workflows/StaticTypeCheck.yml @@ -63,7 +63,7 @@ jobs: StaticTypeCheck: name: 👀 Check Static Typing using Python ${{ inputs.python_version }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository diff --git a/.github/workflows/TestReleaser.yml b/.github/workflows/TestReleaser.yml index 5ee5787..8b7056a 100644 --- a/.github/workflows/TestReleaser.yml +++ b/.github/workflows/TestReleaser.yml @@ -41,7 +41,7 @@ jobs: Image: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: DOCKER_BUILDKIT: 1 steps: @@ -60,7 +60,7 @@ jobs: Composite: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -120,7 +120,7 @@ jobs: needs: - Image - Composite - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/UnitTesting.yml b/.github/workflows/UnitTesting.yml index f51b8cf..52fcc46 100644 --- a/.github/workflows/UnitTesting.yml +++ b/.github/workflows/UnitTesting.yml @@ -29,21 +29,56 @@ on: description: 'JSON list with environment fields, telling the system and Python versions to run tests with.' required: true type: string + apt: + description: 'Ubuntu dependencies to be installed through apt.' + required: false + default: '' + type: string + brew: + description: 'macOS dependencies to be installed through brew.' + required: false + default: '' + type: string + pacboy: + description: 'MSYS2 dependencies to be installed through pacboy (pacman).' + required: false + default: '' + type: string requirements: description: 'Python dependencies to be installed through pip.' required: false default: '-r tests/requirements.txt' type: string - pacboy: - description: 'MSYS2 dependencies to be installed through pacboy (pacman).' - required: false - default: "" - type: string mingw_requirements: description: 'Override Python dependencies to be installed through pip on MSYS2 (MINGW64) only.' required: false default: '' type: string + macos_before_script: + description: 'Scripts to execute before pytest on macOS (Intel).' + required: false + default: '' + type: string + macos_arm_before_script: + description: 'Scripts to execute before pytest on macOS (ARM).' + required: false + default: '' + type: string + ubuntu_before_script: + description: 'Scripts to execute before pytest on Ubuntu.' + required: false + default: '' + type: string + mingw64_before_script: + description: 'Scripts to execute before pytest on Windows within MSYS2 MinGW64.' + required: false + default: '' + type: string + ucrt64_before_script: + description: 'Scripts to execute before pytest on Windows within MSYS2 UCRT64.' + required: false + default: '' + type: string root_directory: description: 'Working directory for running tests.' required: false @@ -113,6 +148,19 @@ jobs: - name: ⏬ Checkout repository uses: actions/checkout@v4 +# Package Manager steps + - name: 🔧 Install homebrew dependencies on macOS + if: ( matrix.system == 'macos' || matrix.system == 'macos-arm' ) && inputs.brew != '' + run: brew install ${{ inputs.brew }} + + - name: 🔧 Install apt dependencies on Ubuntu + if: matrix.system == 'ubuntu' && inputs.apt != '' + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends ${{ inputs.apt }} + +# Compute Dependencies for MSYS2 steps + - name: 🔧 Install dependencies (system Python for Python shell) if: matrix.system == 'msys2' shell: pwsh @@ -149,28 +197,34 @@ jobs: requirements = "${{ inputs.requirements }}" if requirements.startswith("-r"): requirementsFile = Path(requirements[2:].lstrip()) - dependencies = loadRequirementsFile(requirementsFile) + try: + dependencies = loadRequirementsFile(requirementsFile) + except FileNotFoundError as ex: + print(f"::error title=FileNotFoundError::{ex}") + exit(1) else: dependencies = [req.strip() for req in requirements.split(" ")] packages = { - "coverage": "python-coverage:p", - "igraph": "igraph:p", - "jinja2": "python-markupsafe:p", - "lxml": "python-lxml:p", - "numpy": "python-numpy:p", - "markupsafe": "python-markupsafe:p", - "pip": "python-pip:p", - "ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", - "sphinx": "python-markupsafe:p", - "tomli": "python-tomli:p", - "wheel": "python-wheel:p", + "coverage": "python-coverage:p", + "docstr_coverage": "python-pyyaml:p", + "igraph": "igraph:p", + "jinja2": "python-markupsafe:p", + "lxml": "python-lxml:p", + "numpy": "python-numpy:p", + "markupsafe": "python-markupsafe:p", + "pip": "python-pip:p", + "pyyaml": "python-pyyaml:p", + "ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", + "sphinx": "python-markupsafe:p", + "tomli": "python-tomli:p", + "wheel": "python-wheel:p", "pyEDAA.ProjectModel": "python-ruamel-yaml:p python-ruamel.yaml.clib:p python-lxml:p", "pyEDAA.Reports": "python-ruamel-yaml:p python-ruamel.yaml.clib:p python-lxml:p", } subPackages = { "pytooling": { - "yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", + "yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", }, } @@ -206,6 +260,8 @@ jobs: with github_output.open("a+") as f: f.write(f"pacboy_packages={' '.join(pacboyPackages)}\n") +# Python setup + - name: '🟦 Setup MSYS2 for ${{ matrix.runtime }}' if: matrix.system == 'msys2' uses: msys2/setup-msys2@v2 @@ -222,6 +278,8 @@ jobs: with: python-version: ${{ matrix.python }} +# Python Dependency steps + - name: 🔧 Install wheel,tomli and pip dependencies (native) if: matrix.system != 'msys2' run: | @@ -237,6 +295,32 @@ jobs: python -m pip install --disable-pip-version-check ${{ inputs.requirements }} fi +# Before scripts + + - name: 🍎 macOS (Intel) before scripts + if: matrix.system == 'macos' && inputs.macos_before_script != '' + run: ${{ inputs.macos_before_script }} + + - name: 🍏 macOS (ARM) before scripts + if: matrix.system == 'macos-arm' && inputs.macos_arm_before_script != '' + run: ${{ inputs.macos_arm_before_script }} + + - name: 🐧 Ubuntu before scripts + if: matrix.system == 'ubuntu' && inputs.ubuntu_before_script != '' + run: ${{ inputs.ubuntu_before_script }} + + # Windows before script + + - name: 🪟🟦 MinGW64 before scripts + if: matrix.system == 'msys2' && matrix.runtime == 'MINGW64' && inputs.mingw64_before_script != '' + run: ${{ inputs.mingw64_before_script }} + + - name: 🪟🟨 UCRT64 before scripts + if: matrix.system == 'msys2' && matrix.runtime == 'UCRT64' && inputs.ucrt64_before_script != '' + run: ${{ inputs.ucrt64_before_script }} + +# Read pyproject.toml + - name: 🔁 Extract configurations from pyproject.toml id: getVariables shell: python @@ -266,7 +350,9 @@ jobs: xmlFile = Path(pyProjectSettings["tool"]["coverage"]["xml"]["output"]) jsonFile = Path(pyProjectSettings["tool"]["coverage"]["json"]["output"]) else: - print(f"File '{pyProjectFile}' not found and no '.coveragerc' file specified.") + print(f"File '{pyProjectFile}' not found.") + print(f"::error title=FileNotFoundError::File '{pyProjectFile}' not found.") + exit(1) # Read output paths from '.coveragerc' file elif len(coverageRC) > 0: @@ -280,6 +366,8 @@ jobs: jsonFile = Path(coverageRCSettings["json"]["output"]) else: print(f"File '{coverageRCFile}' not found.") + print(f"::error title=FileNotFoundError::File '{coverageRCFile}' not found.") + exit(1) # Write jobs to special file github_output = Path(getenv("GITHUB_OUTPUT")) @@ -294,7 +382,9 @@ jobs: print(f"DEBUG:\n html={htmlDirectory}\n xml={xmlFile}\n json={jsonFile}") - - name: ☑ Run unit tests (Ubuntu/macOS) +# Run pytests + + - name: ✅ Run unit tests (Ubuntu/macOS) if: matrix.system != 'windows' run: | export ENVIRONMENT_NAME="${{ matrix.envname }}" @@ -310,7 +400,7 @@ jobs: python -m pytest -raP $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }} fi - - name: ☑ Run unit tests (Windows) + - name: ✅ Run unit tests (Windows) if: matrix.system == 'windows' run: | $env:ENVIRONMENT_NAME = "${{ matrix.envname }}" @@ -328,20 +418,26 @@ jobs: - name: Convert coverage to XML format (Cobertura) if: inputs.coverage_xml_artifact != '' + continue-on-error: true run: coverage xml --data-file=.coverage - name: Convert coverage to JSON format if: inputs.coverage_json_artifact != '' + continue-on-error: true run: coverage json --data-file=.coverage - name: Convert coverage to HTML format if: inputs.coverage_html_artifact != '' + continue-on-error: true run: | coverage html --data-file=.coverage -d ${{ steps.getVariables.outputs.coverage_report_html_directory }} rm ${{ steps.getVariables.outputs.coverage_report_html_directory }}/.gitignore +# Upload artifacts + - name: 📤 Upload 'TestReportSummary.xml' artifact if: inputs.unittest_xml_artifact != '' + continue-on-error: true uses: actions/upload-artifact@v4 with: name: ${{ inputs.unittest_xml_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }} @@ -366,6 +462,7 @@ jobs: with: name: ${{ inputs.coverage_sqlite_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }} path: .coverage + include-hidden-files: true if-no-files-found: error retention-days: 1 diff --git a/.github/workflows/VerifyDocs.yml b/.github/workflows/VerifyDocs.yml index 5866d84..574f9c5 100644 --- a/.github/workflows/VerifyDocs.yml +++ b/.github/workflows/VerifyDocs.yml @@ -35,7 +35,7 @@ jobs: VerifyDocs: name: 👍 Verify example snippets using Python ${{ inputs.python_version }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: ⏬ Checkout repository @@ -72,7 +72,7 @@ jobs: - name: Print example.py run: cat tests/docs/example.py - - name: ☑ Run example snippet + - name: ✅ Run example snippet working-directory: tests/docs run: | python3 example.py diff --git a/.github/workflows/_Checking_ArtifactCleanup.yml b/.github/workflows/_Checking_ArtifactCleanup.yml index b117324..3d00135 100644 --- a/.github/workflows/_Checking_ArtifactCleanup.yml +++ b/.github/workflows/_Checking_ArtifactCleanup.yml @@ -36,7 +36,7 @@ jobs: name: Package generation needs: - Params - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Package creation run: echo "Package" >> package.txt diff --git a/.github/workflows/_Checking_Parameters.yml b/.github/workflows/_Checking_Parameters.yml index 652ec26..5f3e6ce 100644 --- a/.github/workflows/_Checking_Parameters.yml +++ b/.github/workflows/_Checking_Parameters.yml @@ -64,14 +64,14 @@ jobs: - Params_Exclude - Params_Disable - Params_All - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 defaults: run: shell: python steps: - name: Install dependencies shell: bash - run: pip install pyTooling + run: pip install --disable-pip-version-check --break-system-packages pyTooling # Params_Default - name: Checking results from 'Params_Default' run: | diff --git a/.github/workflows/_Checking_Pipeline.yml b/.github/workflows/_Checking_Pipeline.yml index 77b2179..a1b27e4 100644 --- a/.github/workflows/_Checking_Pipeline.yml +++ b/.github/workflows/_Checking_Pipeline.yml @@ -84,10 +84,12 @@ jobs: codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }} PublishTestResults: - uses: pyTooling/Actions/.github/workflows/PublishTestResults.yml@r1 + uses: pyTooling/Actions/.github/workflows/PublishTestResults.yml@dev needs: - UnitTesting - PlatformTesting + with: + additional_merge_args: '-d "--pytest=rewrite-dunder-init;reduce-depth:pytest.tests.unit;reduce-depth:pytest.tests.platform"' Package: uses: pyTooling/Actions/.github/workflows/Package.yml@r1 diff --git a/.gitignore b/.gitignore index 7ab3de6..aa068cd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ coverage.xml # pytest /report/unit +/tests/*.github # setuptools /build/**/*.* diff --git a/dist/requirements.txt b/dist/requirements.txt new file mode 100644 index 0000000..878e3e5 --- /dev/null +++ b/dist/requirements.txt @@ -0,0 +1,2 @@ +wheel ~= 0.44 +twine ~= 5.1 diff --git a/doc/Action/Releaser.rst b/doc/Action/Releaser.rst index d91b04f..c53c99b 100644 --- a/doc/Action/Releaser.rst +++ b/doc/Action/Releaser.rst @@ -81,7 +81,7 @@ The following block shows a minimal YAML workflow file: jobs: mwe: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: # Clone repository @@ -171,7 +171,7 @@ For prototyping purposes, the following job might be useful: Release: name: '📦 Release' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - ... if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/'>`__) diff --git a/doc/Instantiation.rst b/doc/Instantiation.rst index 254b2d8..3b18faf 100644 --- a/doc/Instantiation.rst +++ b/doc/Instantiation.rst @@ -76,7 +76,7 @@ Documentation Only (Sphinx) needs: - BuildTheDocs - PublishToGitHubPages - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: 🗑️ Delete artifacts diff --git a/doc/JobTemplate/Release.rst b/doc/JobTemplate/Release.rst index 109038c..149ea0d 100644 --- a/doc/JobTemplate/Release.rst +++ b/doc/JobTemplate/Release.rst @@ -12,13 +12,36 @@ This job creates a Release Page on GitHub. **Automated Release created on: ${{ steps.getVariables.outputs.datetime }}** # New Features + + * tbd * tbd # Changes + + * tbd * tbd # Bug Fixes + * tbd + * tbd + + # Documentation + + * tbd + * tbd + + # Unit Tests + + * tbd + * tbd + + ---------- + # Related Issues and Pull-Requests + + * tbd + * tbd + **Behavior:** diff --git a/doc/conf.py b/doc/conf.py index 40b56fe..50f9c22 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -60,10 +60,10 @@ pygments_style = "manni" # ============================================================================== # Restructured Text settings # ============================================================================== -prologPath = "prolog.inc" +prologPath = Path("prolog.inc") try: - with open(prologPath, "r") as prologFile: - rst_prolog = prologFile.read() + with prologPath.open("r", encoding="utf-8") as fileHandle: + rst_prolog = fileHandle.read() except Exception as ex: print(f"[ERROR:] While reading '{prologPath}'.") print(ex) diff --git a/doc/index.rst b/doc/index.rst index 87f4804..0de97bd 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -100,6 +100,9 @@ References - `hdl/containers#48 `__ + +.. _CONTRIBUTORS: + Contributors ************ @@ -108,6 +111,8 @@ Contributors * `and more... `__ +.. _LICENSE: + License ******* diff --git a/doc/requirements.txt b/doc/requirements.txt index f792000..ff21b75 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,10 +1,10 @@ -r ../requirements.txt -pyTooling ~= 6.1 +pyTooling ~= 6.6 # Enforce latest version on ReadTheDocs -sphinx ~= 7.3 -docutils ~= 0.18.0 +sphinx ~= 7.4 +docutils ~= 0.20 # Sphinx Extenstions #sphinx.ext.coverage @@ -16,5 +16,5 @@ sphinxcontrib-mermaid>=0.9.2 autoapi >= 2.0.1 sphinx_fontawesome >= 0.0.6 sphinx-inline-tabs >= 2023.4.21 -sphinx_autodoc_typehints ~= 2.1 +sphinx_autodoc_typehints ~= 2.3 # changelog>=0.3.5 diff --git a/pyproject.toml b/pyproject.toml index 52b2f0f..b32a0f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ [build-system] requires = [ - "setuptools ~= 69.5", - "wheel ~= 0.40.0", - "pyTooling ~= 6.1" + "setuptools ~= 75.1", + "wheel ~= 0.44", + "pyTooling ~= 6.6" ] build-backend = "setuptools.build_meta" diff --git a/releaser/README.md b/releaser/README.md index 33a78cc..3d09e67 100644 --- a/releaser/README.md +++ b/releaser/README.md @@ -75,7 +75,7 @@ on: jobs: mwe: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: # Clone repository @@ -156,7 +156,7 @@ For prototyping purposes, the following job might be useful: ```yml Release: name: '📦 Release' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - ... if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/')) diff --git a/requirements.txt b/requirements.txt index 963d44c..96da06b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pyTooling ~= 6.1 +pyTooling ~= 6.6 diff --git a/tests/pacman_packages.py b/tests/pacman_packages.py new file mode 100644 index 0000000..c570554 --- /dev/null +++ b/tests/pacman_packages.py @@ -0,0 +1,91 @@ +from os import getenv +from pathlib import Path +from re import compile +from sys import version + +print(f"Python: {version}") + + +def loadRequirementsFile(requirementsFile: Path): + requirements = [] + with requirementsFile.open("r") as file: + for line in file.readlines(): + line = line.strip() + if line.startswith("#") or line.startswith("https") or line == "": + continue + elif line.startswith("-r"): + # Remove the first word/argument (-r) + requirements += loadRequirementsFile(requirementsFile.parent / line[2:].lstrip()) + else: + requirements.append(line) + + return requirements + + +requirements = "-r ../tests/requirements.txt" +if requirements.startswith("-r"): + requirementsFile = Path(requirements[2:].lstrip()) + try: + dependencies = loadRequirementsFile(requirementsFile) + except FileNotFoundError as ex: + print(f"::error title=FileNotFound::{ex}") + exit(1) +else: + dependencies = [req.strip() for req in requirements.split(" ")] + +packages = { + "coverage": "python-coverage:p", + "igraph": "igraph:p", + "jinja2": "python-markupsafe:p", + "lxml": "python-lxml:p", + "numpy": "python-numpy:p", + "markupsafe": "python-markupsafe:p", + "pip": "python-pip:p", + "ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", + "sphinx": "python-markupsafe:p", + "tomli": "python-tomli:p", + "wheel": "python-wheel:p", + "pyEDAA.ProjectModel": "python-ruamel-yaml:p python-ruamel.yaml.clib:p python-lxml:p", + "pyEDAA.Reports": "python-ruamel-yaml:p python-ruamel.yaml.clib:p python-lxml:p", +} +subPackages = { + "pytooling": { + "yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p", + }, +} + +regExp = compile( + r"(?P[\w_\-\.]+)(?:\[(?P(?:\w+)(?:\s*,\s*\w+)*)\])?(?:\s*(?P[<>~=]+)\s*)(?P\d+(?:\.\d+)*)(?:-(?P\w+))?") + +pacboyPackages = set(("python-pip:p", "python-wheel:p", "python-tomli:p")) +print(f"Processing dependencies ({len(dependencies)}):") +for dependency in dependencies: + print(f" {dependency}") + + match = regExp.match(dependency.lower()) + if not match: + print(f" Wrong format: {dependency}") + print(f"::error title=Identifying Pacboy Packages::Unrecognized dependency format '{dependency}'") + continue + + package = match["PackageName"] + if package in packages: + rewrite = packages[package] + print(f" Found rewrite rule for '{package}': {rewrite}") + pacboyPackages.add(rewrite) + + if match["SubPackages"] and package in subPackages: + for subPackage in match["SubPackages"].split(","): + if subPackage in subPackages[package]: + rewrite = subPackages[package][subPackage] + print(f" Found rewrite rule for '{package}[..., {subPackage}, ...]': {rewrite}") + pacboyPackages.add(rewrite) + +# Write jobs to special file +github_output = Path(getenv("GITHUB_OUTPUT")) +print(f"GITHUB_OUTPUT: {github_output}") +with github_output.open("a+") as f: + f.write(f"pacboy_packages={' '.join(pacboyPackages)}\n") + +print(f"GITHUB_OUTPUT:") +print(f"pacboy_packages={' '.join(pacboyPackages)}\n") diff --git a/tests/python_jobs.py b/tests/python_jobs.py new file mode 100644 index 0000000..58ec322 --- /dev/null +++ b/tests/python_jobs.py @@ -0,0 +1,216 @@ +from json import dumps as json_dumps +from os import getenv +from pathlib import Path +from textwrap import dedent +from typing import Iterable + +name = "example".strip() +python_version = "3.12".strip() +systems = "ubuntu windows macos-arm mingw64 ucrt64".strip() +versions = "3.8 3.9 3.10 3.11 3.12".strip() +include_list = "".strip() +exclude_list = "".strip() +disable_list = "".strip() + +currentMSYS2Version = "3.11" +currentAlphaVersion = "3.13" +currentAlphaRelease = "3.13.0-alpha.1" + +if systems == "": + print("::error title=Parameter::system_list is empty.") +else: + systems = [sys.strip() for sys in systems.split(" ")] + +if versions == "": + versions = [python_version] +else: + versions = [ver.strip() for ver in versions.split(" ")] + +if include_list == "": + includes = [] +else: + includes = [tuple(include.strip().split(":")) for include in include_list.split(" ")] + +if exclude_list == "": + excludes = [] +else: + excludes = [exclude.strip() for exclude in exclude_list.split(" ")] + +if disable_list == "": + disabled = [] +else: + disabled = [disable.strip() for disable in disable_list.split(" ")] + +if "3.7" in versions: + print("::warning title=Deprecated::Support for Python 3.7 ended in 2023.06.27.") +if "msys2" in systems: + print("::warning title=Deprecated::System 'msys2' will be replaced by 'mingw64'.") +if currentAlphaVersion in versions: + print(f"::notice title=Experimental::Python {currentAlphaVersion} ({currentAlphaRelease}) is a pre-release.") +for disable in disabled: + print(f"::warning title=Disabled Python Job::System '{disable}' temporarily disabled.") + +# see https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json +data = { + # Python and PyPy versions supported by "setup-python" action + "python": { + "3.7": {"icon": "⚫", "until": "2023.06.27"}, + "3.8": {"icon": "🔴", "until": "2024.10"}, + "3.9": {"icon": "🟠", "until": "2025.10"}, + "3.10": {"icon": "🟡", "until": "2026.10"}, + "3.11": {"icon": "🟢", "until": "2027.10"}, + "3.12": {"icon": "🟢", "until": "2028.10"}, + # "3.13": { "icon": "🟣", "until": "2028.10" }, + "pypy-3.7": {"icon": "⟲⚫", "until": "????.??"}, + "pypy-3.8": {"icon": "⟲🔴", "until": "????.??"}, + "pypy-3.9": {"icon": "⟲🟠", "until": "????.??"}, + "pypy-3.10": {"icon": "⟲🟡", "until": "????.??"}, + }, + # Runner systems (runner images) supported by GitHub Actions + "sys": { + "ubuntu": {"icon": "🐧", "runs-on": "ubuntu-24.04", "shell": "bash", "name": "Linux (x86-64)"}, + "windows": {"icon": "🪟", "runs-on": "windows-latest", "shell": "pwsh", "name": "Windows (x86-64)"}, + "macos": {"icon": "🍎", "runs-on": "macos-latest-large", "shell": "bash", "name": "macOS (x86-64)"}, + "macos-arm": {"icon": "🍏", "runs-on": "macos-latest", "shell": "bash", "name": "macOS (arm64)"}, + }, + # Runtimes provided by MSYS2 + "runtime": { + "msys": {"icon": "🪟🟪", "name": "Windows+MSYS2 (x86-64) - MSYS"}, + "mingw32": {"icon": "🪟⬛", "name": "Windows+MSYS2 (x86-64) - MinGW32"}, + "mingw64": {"icon": "🪟🟦", "name": "Windows+MSYS2 (x86-64) - MinGW64"}, + "clang32": {"icon": "🪟🟫", "name": "Windows+MSYS2 (x86-64) - Clang32"}, + "clang64": {"icon": "🪟🟧", "name": "Windows+MSYS2 (x86-64) - Clang64"}, + "ucrt64": {"icon": "🪟🟨", "name": "Windows+MSYS2 (x86-64) - UCRT64"}, + } +} + +print(f"includes ({len(includes)}):") +for system, version in includes: + print(f"- {system}:{version}") +print(f"excludes ({len(excludes)}):") +for exclude in excludes: + print(f"- {exclude}") +print(f"disabled ({len(disabled)}):") +for disable in disabled: + print(f"- {disable}") + + +def match(combination: str, pattern: str) -> bool: + system, version = combination.split(":") + sys, ver = pattern.split(":") + + if sys == "*": + return (ver == "*") or (version == ver) + elif system == sys: + return (ver == "*") or (version == ver) + else: + return False + + +def notIn(combination: str, patterns: Iterable[str]) -> bool: + for pattern in patterns: + if match(combination, pattern): + return False + + return True + +combinations = [ + (system, version) + for system in systems + if system in data["sys"] + for version in versions + if version in data["python"] + and notIn(f"{system}:{version}", excludes) + and notIn(f"{system}:{version}", disabled) + ] + [ + (system, currentMSYS2Version) + for system in systems + if system in data["runtime"] + and notIn(f"{system}:{currentMSYS2Version}", excludes) + and notIn(f"{system}:{currentMSYS2Version}", disabled) + ] + [ + (system, version) + for system, version in includes + if system in data["sys"] + and version in data["python"] + and notIn(f"{system}:{version}", disabled) + ] +print(f"Combinations ({len(combinations)}):") +for system, version in combinations: + print(f"- {system}:{version}") + +jobs = [ + { + "sysicon": data["sys"][system]["icon"], + "system": system, + "runs-on": data["sys"][system]["runs-on"], + "runtime": "native", + "shell": data["sys"][system]["shell"], + "pyicon": data["python"][version]["icon"], + "python": currentAlphaRelease if version == currentAlphaVersion else version, + "envname": data["sys"][system]["name"], + } + for system, version in combinations if system in data["sys"] + ] + [ + { + "sysicon": data["runtime"][runtime]["icon"], + "system": "msys2", + "runs-on": "windows-latest", + "runtime": runtime.upper(), + "shell": "msys2 {0}", + "pyicon": data["python"][currentMSYS2Version]["icon"], + "python": version, + "envname": data["runtime"][runtime]["name"], + } + for runtime, version in combinations if runtime not in data["sys"] + ] + +artifact_names = { + "unittesting_xml": f"{name}-UnitTestReportSummary-XML", + "unittesting_html": f"{name}-UnitTestReportSummary-HTML", + "perftesting_xml": f"{name}-PerformanceTestReportSummary-XML", + "benchtesting_xml": f"{name}-BenchmarkTestReportSummary-XML", + "apptesting_xml": f"{name}-ApplicationTestReportSummary-XML", + "codecoverage_sqlite": f"{name}-CodeCoverage-SQLite", + "codecoverage_xml": f"{name}-CodeCoverage-XML", + "codecoverage_json": f"{name}-CodeCoverage-JSON", + "codecoverage_html": f"{name}-CodeCoverage-HTML", + "statictyping_html": f"{name}-StaticTyping-HTML", + "package_all": f"{name}-Packages", + "documentation_html": f"{name}-Documentation-HTML", + "documentation_latex": f"{name}-Documentation-LaTeX", + "documentation_pdf": f"{name}-Documentation-PDF", +} + +# Deprecated structure +params = { + "python_version": python_version, + "artifacts": { + "unittesting": f"{artifact_names['unittesting_xml']}", + "coverage": f"{artifact_names['codecoverage_html']}", + "typing": f"{artifact_names['statictyping_html']}", + "package": f"{artifact_names['package_all']}", + "doc": f"{artifact_names['documentation_html']}", + } +} + +print("Parameters:") +print(f" python_version: {python_version}") +print(f" python_jobs ({len(jobs)}):\n" + + "".join( + [f" {{ " + ", ".join([f"\"{key}\": \"{value}\"" for key, value in job.items()]) + f" }},\n" for job in jobs]) + ) +print(f" artifact_names ({len(artifact_names)}):") +for id, name in artifact_names.items(): + print(f" {id:>20}: {name}") + +# Write jobs to special file +github_output = Path(getenv("GITHUB_OUTPUT")) +print(f"GITHUB_OUTPUT: {github_output}") +with github_output.open("a+", encoding="utf-8") as f: + f.write(dedent(f"""\ + python_version={python_version} + python_jobs={json_dumps(jobs)} + artifact_names={json_dumps(artifact_names)} + params={json_dumps(params)} +""")) diff --git a/tests/requirements.txt b/tests/requirements.txt index 285ff1a..77e2f22 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,13 +1,13 @@ -r ../requirements.txt # Coverage collection -Coverage ~= 7.5 +Coverage ~= 7.6 # Test Runner -pytest ~= 8.1 +pytest ~= 8.3 pytest-cov ~= 5.0 # Static Type Checking -mypy ~= 1.10 -typing_extensions ~= 4.11 -lxml ~= 5.1 +mypy ~= 1.11 +typing_extensions ~= 4.12 +lxml ~= 5.3