diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000..dc436e9 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,6 @@ +coverage: + status: + project: + default: + target: 0% + threshold: null diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 851dd32..dc1239a 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -10,55 +10,25 @@ jobs: build-n-publish: name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/statick-web + permissions: + id-token: write steps: - - uses: actions/checkout@master + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - - - uses: actions/cache@v3 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - uses: actions/cache@v3 - if: startsWith(runner.os, 'macOS') - with: - path: ~/Library/Caches/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - uses: actions/cache@v3 - if: startsWith(runner.os, 'Windows') - with: - path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Install tools - run: | - python -m pip install --upgrade setuptools - python -m pip install --upgrade wheel + cache: 'pip' - name: Build a binary wheel and a source tarball run: | - python setup.py sdist bdist_wheel - - - name: Publish distribution 📦 to Test PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_TEST_TOKEN }} - repository_url: https://test.pypi.org/legacy/ + pip install -q build + python -m build - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 5821b05..eb7c9fa 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -14,62 +14,29 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-20.04, ubuntu-22.04, windows-latest] - python-version: ['3.8', '3.9', '3.10', '3.11'] + os: [macos-latest, ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, windows-latest] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: '20' - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - uses: actions/cache@v3 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - uses: actions/cache@v3 - if: startsWith(runner.os, 'macOS') - with: - path: ~/Library/Caches/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - uses: actions/cache@v3 - if: startsWith(runner.os, 'Windows') - with: - path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - name: Install dependencies run: | - python -m pip install --upgrade pip - python -m pip install --upgrade setuptools - python -m pip install --upgrade wheel - python -m pip install --upgrade coverage - python -m pip install --upgrade mypy - python -m pip install --upgrade statick - python -m pip install --upgrade statick-md - python -m pip install --upgrade tox - python -m pip install --upgrade tox-gh-actions - python -m pip install --upgrade virtualenv - python -m pip install -r requirements.txt + pip install --upgrade pip + pip install .[docs,test] # Have to install newer version from non-apt source due to SSL library compatibility issues. - name: Install tools (Linux) - if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04' + if: runner.os == 'Linux' run: | npm install -g eslint # eslint plugins and configs should be installed locally @@ -95,7 +62,7 @@ jobs: mypy --ignore-missing-imports --strict src/ - name: Tox - if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04' + if: runner.os == 'Linux' run: | npm list npm list --prefix $HOME/.node_modules @@ -108,12 +75,12 @@ jobs: fail_ci_if_error: false - name: Statick Documentation - if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04' + if: runner.os == 'Linux' run: | statick . --check --profile documentation.yaml - name: Self check - if: matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04' + if: runner.os == 'Linux' run: | mkdir statick-output statick . --output-directory statick-output --check --profile self_check.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index beb7587..5e8e665 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## Unreleased +### Added + +- Support for Python 3.12 and 3.13. +- Use of `pyproject.toml` instead of `setup.py` and `requirements.txt`. +- Supports new plugin discovery mechanism for the main Statick tool. + - Switched from yapsy to setuptools for plugin mechanism. (sscpac/statick#508) + +### Changed + +- Disabled code coverage requirements in CI for now. + - Unable to get line coverage working with new plugin mechanism. + Unit tests still work to find problems. +- Rename plugin modules so they are shorter and less redundant. + +### Removed + +- No longer support Python 3.8. + ## v0.2.0 - 2025-01-03 ### Changed diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..57fb93f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,67 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "statick-web" +authors = [{name = "NIWC Pacific"}] +description="Statick analysis plugins for Web (css, html, js) files." +version = "0.2.0" +readme = "README.md" +requires-python = ">=3.9" +license = {text = "CC0-1.0"} +classifiers = [ + "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development :: Quality Assurance", + "Topic :: Software Development :: Testing", + "Typing :: Typed", +] + +dependencies = [ + "importlib_metadata", + "statick", +] + +[tool.setuptools.package-data] +statick_tool = [ + "rsc/*", + "rsc/.*", +] + +[project.entry-points."statick_tool.plugins.discovery"] +css = "statick_tool.plugins.discovery.css:CSSDiscoveryPlugin" +html = "statick_tool.plugins.discovery.html:HTMLDiscoveryPlugin" +javascript = "statick_tool.plugins.discovery.javascript:JavaScriptDiscoveryPlugin" + +[project.entry-points."statick_tool.plugins.tool"] +eslint = "statick_tool.plugins.tool.eslint:ESLintToolPlugin" +htmllint = "statick_tool.plugins.tool.htmllint:HTMLLintToolPlugin" +jshint = "statick_tool.plugins.tool.jshint:JSHintToolPlugin" +stylelint = "statick_tool.plugins.tool.stylelint:StylelintToolPlugin" + +[project.urls] +"Homepage" = "https://github.com/sscpac/statick-web" +"Bug Tracker" = "https://github.com/sscpac/statick-web/issues" + +[project.optional-dependencies] +test = [ + "coverage", + "mock", + "pytest", + "pytest-cov", + "statick-md@git+https://github.com/tdenewiler/statick-md@stdlib-plugins", + "tox", + "tox-gh-actions", +] +docs = [ + "yaml-1.3", +] + +[tool.isort] +profile = "black" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 15f3587..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -statick diff --git a/setup.py b/setup.py deleted file mode 100644 index 59dc45d..0000000 --- a/setup.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Setup.""" - -from setuptools import setup - -with open("README.md", encoding="utf8") as fid: - long_description = fid.read() # pylint: disable=invalid-name - -TEST_DEPS = [ - "mock", - "pytest", -] - -EXTRAS = { - "test": TEST_DEPS, -} - -setup( - author="NIWC Pacific", - name="statick-web", - description="Statick analysis plugins for Web (css, html, js) files.", - version="0.2.0", - packages=[ - "statick_tool", - "statick_tool.plugins.discovery", - "statick_tool.plugins.tool", - ], - package_dir={ - "statick_tool": ".", - "statick_tool.plugins.discovery": "src/statick_web/plugins/discovery", - "statick_tool.plugins.tool": "src/statick_web/plugins/tool", - }, - package_data={ - "statick_tool": ["rsc/.*", "rsc/*"], - "statick_tool.plugins.discovery": ["*.yapsy-plugin"], - "statick_tool.plugins.tool": ["*.yapsy-plugin"], - }, - long_description=long_description, - long_description_content_type="text/markdown", - install_requires=["statick"], - tests_require=TEST_DEPS, - extras_require=EXTRAS, - url="https://github.com/sscpac/statick-web", - classifiers=[ - "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Topic :: Software Development :: Testing", - ], -) diff --git a/src/statick_web/plugins/discovery/css_discovery_plugin.py b/src/statick_tool/plugins/discovery/css.py similarity index 100% rename from src/statick_web/plugins/discovery/css_discovery_plugin.py rename to src/statick_tool/plugins/discovery/css.py diff --git a/src/statick_web/plugins/discovery/html_discovery_plugin.py b/src/statick_tool/plugins/discovery/html.py similarity index 100% rename from src/statick_web/plugins/discovery/html_discovery_plugin.py rename to src/statick_tool/plugins/discovery/html.py diff --git a/src/statick_web/plugins/discovery/javascript_discovery_plugin.py b/src/statick_tool/plugins/discovery/javascript.py similarity index 100% rename from src/statick_web/plugins/discovery/javascript_discovery_plugin.py rename to src/statick_tool/plugins/discovery/javascript.py diff --git a/src/statick_web/plugins/tool/eslint_tool_plugin.py b/src/statick_tool/plugins/tool/eslint.py similarity index 100% rename from src/statick_web/plugins/tool/eslint_tool_plugin.py rename to src/statick_tool/plugins/tool/eslint.py diff --git a/src/statick_web/plugins/tool/htmllint_tool_plugin.py b/src/statick_tool/plugins/tool/htmllint.py similarity index 100% rename from src/statick_web/plugins/tool/htmllint_tool_plugin.py rename to src/statick_tool/plugins/tool/htmllint.py diff --git a/src/statick_web/plugins/tool/jshint_tool_plugin.py b/src/statick_tool/plugins/tool/jshint.py similarity index 100% rename from src/statick_web/plugins/tool/jshint_tool_plugin.py rename to src/statick_tool/plugins/tool/jshint.py diff --git a/src/statick_web/plugins/tool/stylelint_tool_plugin.py b/src/statick_tool/plugins/tool/stylelint.py similarity index 100% rename from src/statick_web/plugins/tool/stylelint_tool_plugin.py rename to src/statick_tool/plugins/tool/stylelint.py diff --git a/rsc/.htmllintrc b/src/statick_tool/rsc/.htmllintrc similarity index 100% rename from rsc/.htmllintrc rename to src/statick_tool/rsc/.htmllintrc diff --git a/rsc/.jshintrc b/src/statick_tool/rsc/.jshintrc similarity index 100% rename from rsc/.jshintrc rename to src/statick_tool/rsc/.jshintrc diff --git a/rsc/.stylelintrc b/src/statick_tool/rsc/.stylelintrc similarity index 100% rename from rsc/.stylelintrc rename to src/statick_tool/rsc/.stylelintrc diff --git a/rsc/eslint-profile.yaml b/src/statick_tool/rsc/eslint-profile.yaml similarity index 100% rename from rsc/eslint-profile.yaml rename to src/statick_tool/rsc/eslint-profile.yaml diff --git a/rsc/eslint.config.mjs b/src/statick_tool/rsc/eslint.config.mjs similarity index 100% rename from rsc/eslint.config.mjs rename to src/statick_tool/rsc/eslint.config.mjs diff --git a/rsc/htmllint-profile.yaml b/src/statick_tool/rsc/htmllint-profile.yaml similarity index 100% rename from rsc/htmllint-profile.yaml rename to src/statick_tool/rsc/htmllint-profile.yaml diff --git a/rsc/jshint-profile.yaml b/src/statick_tool/rsc/jshint-profile.yaml similarity index 100% rename from rsc/jshint-profile.yaml rename to src/statick_tool/rsc/jshint-profile.yaml diff --git a/rsc/stylelint-profile.yaml b/src/statick_tool/rsc/stylelint-profile.yaml similarity index 100% rename from rsc/stylelint-profile.yaml rename to src/statick_tool/rsc/stylelint-profile.yaml diff --git a/rsc/web-config.yaml b/src/statick_tool/rsc/web-config.yaml similarity index 100% rename from rsc/web-config.yaml rename to src/statick_tool/rsc/web-config.yaml diff --git a/rsc/web-profile.yaml b/src/statick_tool/rsc/web-profile.yaml similarity index 100% rename from rsc/web-profile.yaml rename to src/statick_tool/rsc/web-profile.yaml diff --git a/src/statick_web/__init__.py b/src/statick_web/__init__.py deleted file mode 100644 index 5da5b0e..0000000 --- a/src/statick_web/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Statick tool.""" diff --git a/src/statick_web/plugins/__init__.py b/src/statick_web/plugins/__init__.py deleted file mode 100644 index 9a6d2e7..0000000 --- a/src/statick_web/plugins/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Web plugins for Statick.""" diff --git a/src/statick_web/plugins/discovery/__init__.py b/src/statick_web/plugins/discovery/__init__.py deleted file mode 100644 index 9cef358..0000000 --- a/src/statick_web/plugins/discovery/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Web file discovery plugins.""" diff --git a/src/statick_web/plugins/discovery/css_discovery_plugin.yapsy-plugin b/src/statick_web/plugins/discovery/css_discovery_plugin.yapsy-plugin deleted file mode 100644 index c7ee669..0000000 --- a/src/statick_web/plugins/discovery/css_discovery_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = CSS Discovery Plugin -Module = css_discovery_plugin diff --git a/src/statick_web/plugins/discovery/html_discovery_plugin.yapsy-plugin b/src/statick_web/plugins/discovery/html_discovery_plugin.yapsy-plugin deleted file mode 100644 index 3709de0..0000000 --- a/src/statick_web/plugins/discovery/html_discovery_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = HTML Discovery Plugin -Module = html_discovery_plugin diff --git a/src/statick_web/plugins/discovery/javascript_discovery_plugin.yapsy-plugin b/src/statick_web/plugins/discovery/javascript_discovery_plugin.yapsy-plugin deleted file mode 100644 index 4615f89..0000000 --- a/src/statick_web/plugins/discovery/javascript_discovery_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = JavaScript Discovery Plugin -Module = javascript_discovery_plugin diff --git a/src/statick_web/plugins/tool/__init__.py b/src/statick_web/plugins/tool/__init__.py deleted file mode 100644 index a4744d1..0000000 --- a/src/statick_web/plugins/tool/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Web tool plugins.""" diff --git a/src/statick_web/plugins/tool/eslint_tool_plugin.yapsy-plugin b/src/statick_web/plugins/tool/eslint_tool_plugin.yapsy-plugin deleted file mode 100644 index a64ce9d..0000000 --- a/src/statick_web/plugins/tool/eslint_tool_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = ESLint Tool Plugin -Module = eslint_tool_plugin diff --git a/src/statick_web/plugins/tool/htmllint_tool_plugin.yapsy-plugin b/src/statick_web/plugins/tool/htmllint_tool_plugin.yapsy-plugin deleted file mode 100644 index a4dd101..0000000 --- a/src/statick_web/plugins/tool/htmllint_tool_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = HTMLLint Tool Plugin -Module = htmllint_tool_plugin diff --git a/src/statick_web/plugins/tool/jshint_tool_plugin.yapsy-plugin b/src/statick_web/plugins/tool/jshint_tool_plugin.yapsy-plugin deleted file mode 100644 index 417de52..0000000 --- a/src/statick_web/plugins/tool/jshint_tool_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = JSHint Tool Plugin -Module = jshint_tool_plugin diff --git a/src/statick_web/plugins/tool/stylelint_tool_plugin.yapsy-plugin b/src/statick_web/plugins/tool/stylelint_tool_plugin.yapsy-plugin deleted file mode 100644 index beb11b2..0000000 --- a/src/statick_web/plugins/tool/stylelint_tool_plugin.yapsy-plugin +++ /dev/null @@ -1,3 +0,0 @@ -[Core] -Name = stylelint Tool Plugin -Module = stylelint_tool_plugin diff --git a/tests/discovery/css_discovery_plugin/test_css_discovery_plugin.py b/tests/discovery/css_discovery_plugin/test_css_discovery_plugin.py index c96638e..1c11180 100644 --- a/tests/discovery/css_discovery_plugin/test_css_discovery_plugin.py +++ b/tests/discovery/css_discovery_plugin/test_css_discovery_plugin.py @@ -1,39 +1,28 @@ """Unit tests for the CSS discovery plugin.""" import os +import sys -from yapsy.PluginManager import PluginManager - -import statick_tool -from statick_tool.discovery_plugin import DiscoveryPlugin from statick_tool.exceptions import Exceptions from statick_tool.package import Package -from statick_tool.plugins.discovery.css_discovery_plugin import CSSDiscoveryPlugin + +from statick_tool.plugins.discovery.css import CSSDiscoveryPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def test_css_plugin_found(): """Test that the plugin manager finds the css discovery plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Discovery": DiscoveryPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "css" - assert any( - plugin_info.plugin_object.get_name() == "css" - for plugin_info in manager.getPluginsOfCategory("Discovery") - ) - # While we're at it, verify that a plugin is named CSS Discovery Plugin + discovery_plugins = {} + plugins = entry_points(group="statick_tool.plugins.discovery") + for plugin_type in plugins: + plugin = plugin_type.load() + discovery_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "CSS Discovery Plugin" - for plugin_info in manager.getPluginsOfCategory("Discovery") + plugin.get_name() == "css" for _, plugin in list(discovery_plugins.items()) ) diff --git a/tests/discovery/html_discovery_plugin/test_html_discovery_plugin.py b/tests/discovery/html_discovery_plugin/test_html_discovery_plugin.py index 02efabd..5316ea9 100644 --- a/tests/discovery/html_discovery_plugin/test_html_discovery_plugin.py +++ b/tests/discovery/html_discovery_plugin/test_html_discovery_plugin.py @@ -1,39 +1,28 @@ """Unit tests for the HTML discovery plugin.""" import os +import sys -from yapsy.PluginManager import PluginManager - -import statick_tool -from statick_tool.discovery_plugin import DiscoveryPlugin from statick_tool.exceptions import Exceptions from statick_tool.package import Package -from statick_tool.plugins.discovery.html_discovery_plugin import HTMLDiscoveryPlugin + +from statick_tool.plugins.discovery.html import HTMLDiscoveryPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def test_html_plugin_found(): """Test that the plugin manager finds the html discovery plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Discovery": DiscoveryPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "html" - assert any( - plugin_info.plugin_object.get_name() == "html" - for plugin_info in manager.getPluginsOfCategory("Discovery") - ) - # While we're at it, verify that a plugin is named html Discovery Plugin + discovery_plugins = {} + plugins = entry_points(group="statick_tool.plugins.discovery") + for plugin_type in plugins: + plugin = plugin_type.load() + discovery_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "HTML Discovery Plugin" - for plugin_info in manager.getPluginsOfCategory("Discovery") + plugin.get_name() == "html" for _, plugin in list(discovery_plugins.items()) ) diff --git a/tests/discovery/javascript_discovery_plugin/test_javascript_discovery_plugin.py b/tests/discovery/javascript_discovery_plugin/test_javascript_discovery_plugin.py index c4c2301..11b0a0e 100644 --- a/tests/discovery/javascript_discovery_plugin/test_javascript_discovery_plugin.py +++ b/tests/discovery/javascript_discovery_plugin/test_javascript_discovery_plugin.py @@ -1,41 +1,29 @@ """Unit tests for the JavaScript discovery plugin.""" import os +import sys -from yapsy.PluginManager import PluginManager - -import statick_tool -from statick_tool.discovery_plugin import DiscoveryPlugin from statick_tool.exceptions import Exceptions from statick_tool.package import Package -from statick_tool.plugins.discovery.javascript_discovery_plugin import ( - JavaScriptDiscoveryPlugin, -) + +from statick_tool.plugins.discovery.javascript import JavaScriptDiscoveryPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def test_javascript_plugin_found(): """Test that the plugin manager finds the JavaScript discovery plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Discovery": DiscoveryPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "javascript" - assert any( - plugin_info.plugin_object.get_name() == "javascript" - for plugin_info in manager.getPluginsOfCategory("Discovery") - ) - # While we're at it, verify that a plugin is named javascript Discovery Plugin + discovery_plugins = {} + plugins = entry_points(group="statick_tool.plugins.discovery") + for plugin_type in plugins: + plugin = plugin_type.load() + discovery_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "JavaScript Discovery Plugin" - for plugin_info in manager.getPluginsOfCategory("Discovery") + plugin.get_name() == "javascript" + for _, plugin in list(discovery_plugins.items()) ) diff --git a/tests/tool/eslint_tool_plugin/test_eslint_tool_plugin.py b/tests/tool/eslint_tool_plugin/test_eslint_tool_plugin.py index 0e6a7c5..c6db958 100644 --- a/tests/tool/eslint_tool_plugin/test_eslint_tool_plugin.py +++ b/tests/tool/eslint_tool_plugin/test_eslint_tool_plugin.py @@ -3,18 +3,22 @@ import argparse import os import subprocess +import sys import mock import pytest -from yapsy.PluginManager import PluginManager - -import statick_tool from statick_tool.config import Config from statick_tool.package import Package from statick_tool.plugin_context import PluginContext -from statick_tool.plugins.tool.eslint_tool_plugin import ESLintToolPlugin from statick_tool.resources import Resources -from statick_tool.tool_plugin import ToolPlugin + +import statick_tool +from statick_tool.plugins.tool.eslint import ESLintToolPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def setup_eslint_tool_plugin(test_package="valid_package"): @@ -43,27 +47,13 @@ def setup_eslint_tool_plugin(test_package="valid_package"): def test_eslint_tool_plugin_found(): """Test that the plugin manager can find the eslint plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Tool": ToolPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "eslint" - assert any( - plugin_info.plugin_object.get_name() == "eslint" - for plugin_info in manager.getPluginsOfCategory("Tool") - ) - # While we're at it, verify that a plugin is named ESLint Tool Plugin + tool_plugins = {} + plugins = entry_points(group="statick_tool.plugins.tool") + for plugin_type in plugins: + plugin = plugin_type.load() + tool_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "ESLint Tool Plugin" - for plugin_info in manager.getPluginsOfCategory("Tool") + plugin.get_name() == "eslint" for _, plugin in list(tool_plugins.items()) ) @@ -104,7 +94,6 @@ def test_eslint_tool_plugin_scan_valid_with_issues(): def test_eslint_tool_plugin_parse_valid(): """Verify that we can parse the expected output of eslint.""" plugin = setup_eslint_tool_plugin() - # output = "test.js:1:13: Strings must use singlequote. [Error/quotes]" output = '[{"filePath":"test.js","messages":[{"ruleId":"quotes","severity":2,"message":"Strings must use singlequote.","line":1,"column":13,"nodeType":"Identifier","messageId":"notSingleQuote","endLine":1,"endColumn":18,"source":" "}]}]' issues = plugin.parse_output([output]) assert len(issues) == 1 @@ -140,7 +129,7 @@ def test_eslint_tool_plugin_parse_invalid(): assert not issues -@mock.patch("statick_tool.plugins.tool.eslint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.eslint.subprocess.check_output") def test_eslint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_output): """ Test what happens when a CalledProcessError is raised (usually means eslint hit an error). @@ -170,7 +159,7 @@ def test_eslint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_output assert not issues -@mock.patch("statick_tool.plugins.tool.eslint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.eslint.subprocess.check_output") def test_eslint_tool_plugin_scan_nodejs_error(mock_subprocess_check_output): """ Test what happens when a CalledProcessError is raised when nodejs throws an error. @@ -207,7 +196,7 @@ def test_eslint_tool_plugin_scan_nodejs_error(mock_subprocess_check_output): assert issues is None -@mock.patch("statick_tool.plugins.tool.eslint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.eslint.subprocess.check_output") def test_eslint_tool_plugin_scan_oserror(mock_subprocess_check_output): """ Test what happens when an OSError is raised (usually means eslint doesn't exist). diff --git a/tests/tool/htmllint_tool_plugin/test_htmllint_tool_plugin.py b/tests/tool/htmllint_tool_plugin/test_htmllint_tool_plugin.py index c9834ca..d379d44 100644 --- a/tests/tool/htmllint_tool_plugin/test_htmllint_tool_plugin.py +++ b/tests/tool/htmllint_tool_plugin/test_htmllint_tool_plugin.py @@ -3,18 +3,22 @@ import argparse import os import subprocess +import sys import mock import pytest -from yapsy.PluginManager import PluginManager - -import statick_tool from statick_tool.config import Config from statick_tool.package import Package from statick_tool.plugin_context import PluginContext -from statick_tool.plugins.tool.htmllint_tool_plugin import HTMLLintToolPlugin from statick_tool.resources import Resources -from statick_tool.tool_plugin import ToolPlugin + +import statick_tool +from statick_tool.plugins.tool.htmllint import HTMLLintToolPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def setup_htmllint_tool_plugin(): @@ -43,27 +47,13 @@ def setup_htmllint_tool_plugin(): def test_htmllint_tool_plugin_found(): """Test that the plugin manager can find the htmllint plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Tool": ToolPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "htmllint" - assert any( - plugin_info.plugin_object.get_name() == "htmllint" - for plugin_info in manager.getPluginsOfCategory("Tool") - ) - # While we're at it, verify that a plugin is named htmllint Tool Plugin + tool_plugins = {} + plugins = entry_points(group="statick_tool.plugins.tool") + for plugin_type in plugins: + plugin = plugin_type.load() + tool_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "HTMLLint Tool Plugin" - for plugin_info in manager.getPluginsOfCategory("Tool") + plugin.get_name() == "htmllint" for _, plugin in list(tool_plugins.items()) ) @@ -120,7 +110,7 @@ def test_htmllint_tool_plugin_parse_invalid(): assert not issues -@mock.patch("statick_tool.plugins.tool.htmllint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.htmllint.subprocess.check_output") def test_htmllint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_output): """ Test what happens when a CalledProcessError is raised (usually means htmllint hit an error). @@ -147,7 +137,7 @@ def test_htmllint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_outp assert not issues -@mock.patch("statick_tool.plugins.tool.htmllint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.htmllint.subprocess.check_output") def test_htmllint_tool_plugin_scan_nodejs_error(mock_subprocess_check_output): """ Test what happens when a CalledProcessError is raised when nodejs throws an error. @@ -162,7 +152,7 @@ def test_htmllint_tool_plugin_scan_nodejs_error(mock_subprocess_check_output): ^ \ \ Error: Cannot find module 'node:fs' \ -Require stack:", +Require stack:" ) plugin = setup_htmllint_tool_plugin() package = Package( @@ -181,7 +171,7 @@ def test_htmllint_tool_plugin_scan_nodejs_error(mock_subprocess_check_output): assert issues is None -@mock.patch("statick_tool.plugins.tool.htmllint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.htmllint.subprocess.check_output") def test_htmllint_tool_plugin_scan_oserror(mock_subprocess_check_output): """ Test what happens when an OSError is raised (usually means htmllint doesn't exist). diff --git a/tests/tool/jshint_tool_plugin/test_jshint_tool_plugin.py b/tests/tool/jshint_tool_plugin/test_jshint_tool_plugin.py index 9d071de..16a50a4 100644 --- a/tests/tool/jshint_tool_plugin/test_jshint_tool_plugin.py +++ b/tests/tool/jshint_tool_plugin/test_jshint_tool_plugin.py @@ -3,18 +3,22 @@ import argparse import os import subprocess +import sys import mock import pytest -from yapsy.PluginManager import PluginManager - -import statick_tool from statick_tool.config import Config from statick_tool.package import Package from statick_tool.plugin_context import PluginContext -from statick_tool.plugins.tool.jshint_tool_plugin import JSHintToolPlugin from statick_tool.resources import Resources -from statick_tool.tool_plugin import ToolPlugin + +import statick_tool +from statick_tool.plugins.tool.jshint import JSHintToolPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def setup_jshint_tool_plugin(): @@ -43,27 +47,13 @@ def setup_jshint_tool_plugin(): def test_jshint_tool_plugin_found(): """Test that the plugin manager can find the jshint plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Tool": ToolPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "jshint" - assert any( - plugin_info.plugin_object.get_name() == "jshint" - for plugin_info in manager.getPluginsOfCategory("Tool") - ) - # While we're at it, verify that a plugin is named jshint Tool Plugin + tool_plugins = {} + plugins = entry_points(group="statick_tool.plugins.tool") + for plugin_type in plugins: + plugin = plugin_type.load() + tool_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "JSHint Tool Plugin" - for plugin_info in manager.getPluginsOfCategory("Tool") + plugin.get_name() == "jshint" for _, plugin in list(tool_plugins.items()) ) @@ -123,7 +113,7 @@ def test_jshint_tool_plugin_parse_invalid(): assert not issues -@mock.patch("statick_tool.plugins.tool.jshint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.jshint.subprocess.check_output") def test_jshint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_output): """ Test what happens when a CalledProcessError is raised (usually means jshint hit an error). @@ -153,7 +143,7 @@ def test_jshint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_output assert not issues -@mock.patch("statick_tool.plugins.tool.jshint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.jshint.subprocess.check_output") def test_jshint_tool_plugin_scan_oserror(mock_subprocess_check_output): """ Test what happens when an OSError is raised (usually means jshint doesn't exist). diff --git a/tests/tool/stylelint_tool_plugin/test_stylelint_tool_plugin.py b/tests/tool/stylelint_tool_plugin/test_stylelint_tool_plugin.py index 3f6e324..bc15fad 100644 --- a/tests/tool/stylelint_tool_plugin/test_stylelint_tool_plugin.py +++ b/tests/tool/stylelint_tool_plugin/test_stylelint_tool_plugin.py @@ -3,18 +3,22 @@ import argparse import os import subprocess +import sys import mock import pytest -from yapsy.PluginManager import PluginManager - -import statick_tool from statick_tool.config import Config from statick_tool.package import Package from statick_tool.plugin_context import PluginContext -from statick_tool.plugins.tool.stylelint_tool_plugin import StylelintToolPlugin from statick_tool.resources import Resources -from statick_tool.tool_plugin import ToolPlugin + +import statick_tool +from statick_tool.plugins.tool.stylelint import StylelintToolPlugin + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points def setup_stylelint_tool_plugin(): @@ -43,27 +47,13 @@ def setup_stylelint_tool_plugin(): def test_stylelint_tool_plugin_found(): """Test that the plugin manager can find the stylelint plugin.""" - manager = PluginManager() - # Get the path to statick_tool/__init__.py, get the directory part, and - # add 'plugins' to that to get the standard plugins dir - manager.setPluginPlaces( - [os.path.join(os.path.dirname(statick_tool.__file__), "plugins")] - ) - manager.setCategoriesFilter( - { - "Tool": ToolPlugin, - } - ) - manager.collectPlugins() - # Verify that a plugin's get_name() function returns "stylelint" - assert any( - plugin_info.plugin_object.get_name() == "stylelint" - for plugin_info in manager.getPluginsOfCategory("Tool") - ) - # While we're at it, verify that a plugin is named stylelint Tool Plugin + tool_plugins = {} + plugins = entry_points(group="statick_tool.plugins.tool") + for plugin_type in plugins: + plugin = plugin_type.load() + tool_plugins[plugin_type.name] = plugin() assert any( - plugin_info.name == "stylelint Tool Plugin" - for plugin_info in manager.getPluginsOfCategory("Tool") + plugin.get_name() == "stylelint" for _, plugin in list(tool_plugins.items()) ) @@ -126,7 +116,7 @@ def test_stylelint_tool_plugin_parse_invalid(): assert not issues -@mock.patch("statick_tool.plugins.tool.stylelint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.stylelint.subprocess.check_output") def test_stylelint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_output): """ Test what happens when a CalledProcessError is raised (usually means stylelint hit an error). @@ -156,7 +146,7 @@ def test_stylelint_tool_plugin_scan_calledprocesserror(mock_subprocess_check_out assert not issues -@mock.patch("statick_tool.plugins.tool.stylelint_tool_plugin.subprocess.check_output") +@mock.patch("statick_tool.plugins.tool.stylelint.subprocess.check_output") def test_stylelint_tool_plugin_scan_oserror(mock_subprocess_check_output): """ Test what happens when an OSError is raised (usually means stylelint doesn't exist). diff --git a/tox.ini b/tox.ini index 5c50067..14ff8b9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,50 +1,28 @@ [tox] -envlist = py38, py39, py310, py311 +envlist = py39, py310, py311, py312, py313 skip_missing_interpreters = true [pytest] -norecursedirs = .tox - -# To work with black a specific configuration is required. -# https://github.com/psf/black#how-black-wraps-lines -[isort] -known_first_party = statick_tool -multi_line_output = 3 -include_trailing_comma = True -force_grid_wrap = 0 -use_parentheses = True -line_length = 88 +norecursedirs = .tox build [gh-actions] python = - 3.8: py38 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 + 3.13: py313 [testenv] changedir = {toxinidir}/output-{envname} -passenv = CI -setenv = PY_IGNORE_IMPORTMISMATCH = 1 deps = - pycodestyle - pydocstyle - pytest - pytest-cov - pytest-isort .[test] commands = - pydocstyle ../src/ - pycodestyle --ignore=E203,E501,W503 ../src/ - pytest -svv --isort \ - --cov=statick_tool.plugins.discovery.css_discovery_plugin \ - --cov=statick_tool.plugins.discovery.html_discovery_plugin \ - --cov=statick_tool.plugins.discovery.javascript_discovery_plugin \ - --cov=statick_tool.plugins.tool.eslint_tool_plugin \ - --cov=statick_tool.plugins.tool.htmllint_tool_plugin \ - --cov=statick_tool.plugins.tool.jshint_tool_plugin \ - --cov=statick_tool.plugins.tool.stylelint_tool_plugin \ + pytest \ + --cov={toxinidir}/src/statick_tool \ --cov-report term-missing \ --doctest-modules \ + --junit-xml=statick-{envname}-junit.xml \ + --junit-prefix={envname} \ {toxinidir} {posargs} coverage xml