From d4a856c353cd3677c692d1609bd0a1aa31351e36 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Sun, 26 Nov 2023 23:36:29 +0100 Subject: [PATCH 01/11] Configuring with plone/meta --- .editorconfig | 49 +++++- .flake8 | 22 +++ .github/workflows/meta.yml | 68 ++++++++ .gitignore | 74 +++++---- .meta.toml | 6 + .pre-commit-config.yaml | 94 +++++++++++ pyproject.toml | 123 ++++++++++++++ tox.ini | 333 ++++++++++++++++++++----------------- 8 files changed, 581 insertions(+), 188 deletions(-) create mode 100644 .flake8 create mode 100644 .github/workflows/meta.yml create mode 100644 .meta.toml create mode 100644 .pre-commit-config.yaml create mode 100644 pyproject.toml diff --git a/.editorconfig b/.editorconfig index a83363b..8ae05aa 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,15 +1,54 @@ -[*] -indent_style = space +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +# +# EditorConfig Configuration file, for more details see: +# http://EditorConfig.org +# EditorConfig is a convention description, that could be interpreted +# by multiple editors to enforce common coding conventions for specific +# file types + +# top-most EditorConfig file: +# Will ignore other EditorConfig files in Home directory or upper tree level. +root = true + + +[*] # For All Files +# Unix-style newlines with a newline ending every file end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true +# Set default charset charset = utf-8 +# Indent style default +indent_style = space +# Max Line Length - a hard line wrap, should be disabled +max_line_length = off -[{*.py,*.cfg}] +[*.{py,cfg,ini}] +# 4 space indentation indent_size = 4 -[{*.html,*.dtml,*.pt,*.zpt,*.xml,*.zcml,*.js}] +[*.{yml,zpt,pt,dtml,zcml}] +# 2 space indentation indent_size = 2 -[Makefile] +[*.{json,jsonl,js,jsx,ts,tsx,css,less,scss,html}] # Frontend development +# 2 space indentation +indent_size = 2 +max_line_length = 80 + +[{Makefile,.gitmodules}] +# Tab indentation (no size specified, but view as 4 spaces) indent_style = tab +indent_size = unset +tab_width = unset + + +## +# Add extra configuration options in .meta.toml: +# [editorconfig] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..7ef4f64 --- /dev/null +++ b/.flake8 @@ -0,0 +1,22 @@ +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +[flake8] +doctests = 1 +ignore = + # black takes care of line length + E501, + # black takes care of where to break lines + W503, + # black takes care of spaces within slicing (list[:]) + E203, + # black takes care of spaces after commas + E231, + +## +# Add extra configuration options in .meta.toml: +# [flake8] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml new file mode 100644 index 0000000..39a164d --- /dev/null +++ b/.github/workflows/meta.yml @@ -0,0 +1,68 @@ +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +name: Meta +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + workflow_dispatch: + +## +# To set environment variables for all jobs, add in .meta.toml: +# [github] +# env = """ +# debug: 1 +# image-name: 'org/image' +# image-tag: 'latest' +# """ +## + +jobs: + qa: + uses: plone/meta/.github/workflows/qa.yml@main + test: + uses: plone/meta/.github/workflows/test.yml@main + coverage: + uses: plone/meta/.github/workflows/coverage.yml@main + dependencies: + uses: plone/meta/.github/workflows/dependencies.yml@main + release_ready: + uses: plone/meta/.github/workflows/release_ready.yml@main + circular: + uses: plone/meta/.github/workflows/circular.yml@main + +## +# To modify the list of default jobs being created add in .meta.toml: +# [github] +# jobs = [ +# "qa", +# "test", +# "coverage", +# "dependencies", +# "release_ready", +# "circular", +# ] +## + +## +# To request that some OS level dependencies get installed +# when running tests/coverage jobs, add in .meta.toml: +# [github] +# os_dependencies = "git libxml2 libxslt" +## + + +## +# Specify additional jobs in .meta.toml: +# [github] +# extra_lines = """ +# another: +# uses: org/repo/.github/workflows/file.yml@main +# """ +## diff --git a/.gitignore b/.gitignore index 3988bfb..503e47c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,39 +1,55 @@ -.coverage -.coverage.* +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +# python related *.egg-info -*.log +*.pyc +*.pyo + +# translation related *.mo -*.py? -*.swp + +# tools related +build/ +.coverage .*project -# dirs -/.settings/ +coverage.xml +dist/ +docs/_build +__pycache__/ +.tox +.vscode/ +node_modules/ + +# venv / buildout related bin/ -buildout-cache/ develop-eggs/ eggs/ -htmlcov/ +.eggs/ +etc/ +.installed.cfg include/ lib/ -local/ -node_modules/ -parts/ -dist/* -test.plone_addon/ -var/ -# files -.installed.cfg -.mr.developer.cfg -coverage.xml lib64 -local.cfg -log.html -output.xml -pip-selfcheck.json +.mr.developer.cfg +parts/ pyvenv.cfg -report.html -.vscode/ -.tox/ -reports/ -venv/ -# excludes +var/ + +# mxdev +/instance/ +/.make-sentinels/ +/*-mxdev.txt +/reports/ +/sources/ +/venv/ +.installed.txt + + +## +# Add extra configuration options in .meta.toml: +# [gitignore] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.meta.toml b/.meta.toml new file mode 100644 index 0000000..272d4ca --- /dev/null +++ b/.meta.toml @@ -0,0 +1,6 @@ +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +[meta] +template = "default" +commit-id = "8c30aa23" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..f13d059 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,94 @@ +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +ci: + autofix_prs: false + autoupdate_schedule: monthly + +repos: +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + args: [--py38-plus] +- repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort +- repo: https://github.com/psf/black + rev: 23.10.1 + hooks: + - id: black +- repo: https://github.com/collective/zpretty + rev: 3.1.0 + hooks: + - id: zpretty + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# zpretty_extra_lines = """ +# _your own configuration lines_ +# """ +## +- repo: https://github.com/PyCQA/flake8 + rev: 6.1.0 + hooks: + - id: flake8 + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# flake8_extra_lines = """ +# _your own configuration lines_ +# """ +## +- repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + additional_dependencies: + - tomli + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# codespell_extra_lines = """ +# _your own configuration lines_ +# """ +## +- repo: https://github.com/mgedmin/check-manifest + rev: "0.49" + hooks: + - id: check-manifest +- repo: https://github.com/regebro/pyroma + rev: "4.2" + hooks: + - id: pyroma +- repo: https://github.com/mgedmin/check-python-versions + rev: "0.22.0" + hooks: + - id: check-python-versions + args: ['--only', 'setup.py,pyproject.toml'] +- repo: https://github.com/collective/i18ndude + rev: "6.1.0" + hooks: + - id: i18ndude + + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# i18ndude_extra_lines = """ +# _your own configuration lines_ +# """ +## + + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1605056 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,123 @@ +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file +[build-system] +requires = ["setuptools>=68.2"] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# towncrier_extra_lines = """ +# extra_configuration +# """ +## + +[tool.isort] +profile = "plone" + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# isort_extra_lines = """ +# extra_configuration +# """ +## + +[tool.black] +target-version = ["py38"] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# black_extra_lines = """ +# extra_configuration +# """ +## + +[tool.codespell] +ignore-words-list = "discreet," +skip = "*.po," +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# codespell_ignores = "foo,bar" +# codespell_skip = "*.po,*.map,package-lock.json" +## + +[tool.dependencychecker] +Zope = [ + # Zope own provided namespaces + 'App', 'OFS', 'Products.Five', 'Products.OFSP', 'Products.PageTemplates', + 'Products.SiteAccess', 'Shared', 'Testing', 'ZPublisher', 'ZTUtils', + 'Zope2', 'webdav', 'zmi', + # ExtensionClass own provided namespaces + 'ExtensionClass', 'ComputedAttribute', 'MethodObject', + # Zope dependencies + 'AccessControl', 'Acquisition', 'AuthEncoding', 'beautifulsoup4', 'BTrees', + 'cffi', 'Chameleon', 'DateTime', 'DocumentTemplate', + 'MultiMapping', 'multipart', 'PasteDeploy', 'Persistence', 'persistent', + 'pycparser', 'python-gettext', 'pytz', 'RestrictedPython', 'roman', + 'soupsieve', 'transaction', 'waitress', 'WebOb', 'WebTest', 'WSGIProxy2', + 'z3c.pt', 'zc.lockfile', 'ZConfig', 'zExceptions', 'ZODB', 'zodbpickle', + 'zope.annotation', 'zope.browser', 'zope.browsermenu', 'zope.browserpage', + 'zope.browserresource', 'zope.cachedescriptors', 'zope.component', + 'zope.configuration', 'zope.container', 'zope.contentprovider', + 'zope.contenttype', 'zope.datetime', 'zope.deferredimport', + 'zope.deprecation', 'zope.dottedname', 'zope.event', 'zope.exceptions', + 'zope.filerepresentation', 'zope.globalrequest', 'zope.hookable', + 'zope.i18n', 'zope.i18nmessageid', 'zope.interface', 'zope.lifecycleevent', + 'zope.location', 'zope.pagetemplate', 'zope.processlifetime', 'zope.proxy', + 'zope.ptresource', 'zope.publisher', 'zope.schema', 'zope.security', + 'zope.sequencesort', 'zope.site', 'zope.size', 'zope.structuredtext', + 'zope.tal', 'zope.tales', 'zope.testbrowser', 'zope.testing', + 'zope.traversing', 'zope.viewlet' +] +'Products.CMFCore' = [ + 'docutils', 'five.localsitemanager', 'Missing', 'Products.BTreeFolder2', + 'Products.GenericSetup', 'Products.MailHost', 'Products.PythonScripts', + 'Products.StandardCacheManagers', 'Products.ZCatalog', 'Record', + 'zope.sendmail', 'Zope' +] +'plone.base' = [ + 'plone.batching', 'plone.registry', 'plone.schema','plone.z3cform', + 'Products.CMFCore', 'Products.CMFDynamicViewFTI', +] +python-dateutil = ['dateutil'] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# dependencies_ignores = "['zestreleaser.towncrier']" +# dependencies_mappings = [ +# "gitpython = ['git']", +# "pygithub = ['github']", +# ] +## + +[tool.check-manifest] +ignore = [ + ".editorconfig", + ".meta.toml", + ".pre-commit-config.yaml", + "tox.ini", + ".flake8", + "mx.ini", + +] +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# check_manifest_ignores = """ +# "*.map.js", +# "*.pyc", +# """ +## + + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/tox.ini b/tox.ini index 6a7e0ec..81c356d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,186 +1,211 @@ +# Generated from: +# https://github.com/plone/meta/tree/master/config/default +# See the inline comments on how to expand/tweak this configuration file [tox] +# We need 4.4.0 for constrain_package_deps. +min_version = 4.4.0 envlist = - py37-lint, - py38-lint, - py39-lint, - py310-lint, - black-check, - py{38,37}-Plone{52}, - py{39,310}-Plone{60}, -# docs, -# coverage-report, - -skip_missing_interpreters = True - - -[gh-actions] -python = - 3.6: py36 - 3.7: py37 - 3.8: py38 - 3.9: py39 - 3.10: py310 - + lint + test + dependencies -[gh-actions:env] -PLONE-VERSION = - Plone52: Plone52 - Plone60: Plone60 +## +# Add extra configuration options in .meta.toml: +# [tox] +# envlist_lines = """ +# my_other_environment +# """ +# config_lines = """ +# my_extra_top_level_tox_configuration_lines +# """ +## [testenv] skip_install = true - -extras = - develop - test - +allowlist_externals = + echo + false +# Make sure typos like `tox -e formaat` are caught instead of silently doing nothing. +# See https://github.com/tox-dev/tox/issues/2858. commands = - {envbindir}/buildout -q -c {toxinidir}/{env:version_file} buildout:directory={envdir} buildout:develop={toxinidir} bootstrap -# {envbindir}/buildout -c {toxinidir}/{env:version_file} buildout:directory={envdir} buildout:develop={toxinidir} annotate - {envbindir}/buildout -n -qq -c {toxinidir}/{env:version_file} buildout:directory={envdir} buildout:develop={toxinidir} install test robot - coverage run {envbindir}/test -v1 --auto-color {posargs} - # coverage run {envbindir}/test -v --all -t robot {posargs} - -setenv = - COVERAGE_FILE=.coverage.{envname} - # version_file=test_plone60.cfg - Plone52: version_file=test_plone52.cfg - Plone60: version_file=test_plone60.cfg - -deps = - Plone52: -rrequirements_plone52.txt -# Plone52: -cconstraints_plone52.txt - Plone60: -rrequirements_plone60.txt -# Plone60: -cconstraints_plone60.txt - coverage + echo "Unrecognized environment name {envname}" + false + +## +# Add extra configuration options in .meta.toml: +# [tox] +# testenv_options = """ +# basepython = /usr/bin/python3.8 +# """ +## + +[testenv:init] +description = Prepare environment +skip_install = true +commands = + echo "Initial setup complete" -[testenv:coverage-report] +[testenv:format] +description = automatically reformat code skip_install = true -usedevelop = True -basepython = python3.9 - deps = - coverage - -cconstraints_plone60.txt - -setenv = - COVERAGE_FILE=.coverage - + pre-commit commands = - coverage erase - coverage combine - coverage html - coverage xml - coverage report - + pre-commit run -a pyupgrade + pre-commit run -a isort + pre-commit run -a black + pre-commit run -a zpretty -[lint] +[testenv:lint] +description = run linters that will help improve the code style skip_install = true - deps = - -cconstraints.txt - isort - flake8 - # helper to generate HTML reports: - # flake8-html>=0.4.3 - # Useful flake8 plugins that are Python and Plone specific: - ; flake8-coding - flake8-debugger - flake8-deprecated - flake8-print - #flake8-pytest - flake8-todo - mccabe - # Potential flake8 plugins that should be used: # TBD - #flake8-blind-except - #flake8-commas - #flake8-docstrings - #flake8-mypy - #flake8-pep3101 - #flake8-plone-hasattr - #flake8-string-format - #flake8_strict - #flake8-quotes - #flake8-polyfill - + pre-commit commands = - mkdir -p {toxinidir}/reports/flake8 - flake8 --doctests {toxinidir}/src {toxinidir}/setup.py - isort --check-only {toxinidir}/src {toxinidir}/setup.py - # black --check --diff -v {toxinidir}/src {toxinidir}/setup.py - -allowlist_externals = - mkdir - + pre-commit run -a -[testenv:isort-apply] +[testenv:dependencies] +description = check if the package defines all its dependencies skip_install = true - deps = - -cconstraints.txt - isort - + build + z3c.dependencychecker==2.11 commands = - isort {toxinidir}/src {toxinidir}/setup.py - + python -m build --sdist + dependencychecker -[testenv:black-check] -basepython = python3.9 -skip_install = True +[testenv:dependencies-graph] +description = generate a graph out of the dependencies of the package +skip_install = false +allowlist_externals = + sh deps = - -cconstraints.txt - black - + pipdeptree==2.5.1 + graphviz # optional dependency of pipdeptree commands = - black --check --diff -v src setup.py - - -[testenv:black-enforce] -basepython = python3.9 -skip_install = True + sh -c 'pipdeptree --exclude setuptools,wheel,pipdeptree,zope.interface,zope.component --graph-output svg > dependencies.svg' + +[testenv:test] +description = run the distribution tests +use_develop = true +skip_install = false +constrain_package_deps = true +set_env = + ROBOT_BROWSER=headlesschrome + +## +# Specify extra test environment variables in .meta.toml: +# [tox] +# test_environment_variables = """ +# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ +# """ +# +# Set constrain_package_deps .meta.toml: +# [tox] +# constrain_package_deps = "false" +## deps = - -cconstraints.txt - black - + zope.testrunner + -c https://dist.plone.org/release/6.0-dev/constraints.txt + +## +# Specify additional deps in .meta.toml: +# [tox] +# test_deps_additional = "-esources/plonegovbr.portal_base[test]" +# +# Specify a custom constraints file in .meta.toml: +# [tox] +# constraints_file = "https://my-server.com/constraints.txt" +## commands = - black -v src setup.py - - -[testenv:py37-lint] -basepython = python3.7 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -allowlist_externals = {[lint]allowlist_externals} - -[testenv:py38-lint] -basepython = python3.8 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -allowlist_externals = {[lint]allowlist_externals} + zope-testrunner --all --test-path={toxinidir}/src -s pas.plugins.passwordstrength {posargs} +extras = + test -[testenv:py39-lint] -basepython = python3.9 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -allowlist_externals = {[lint]allowlist_externals} +## +# Add extra configuration options in .meta.toml: +# [tox] +# test_extras = """ +# tests +# widgets +# """ +## + +[testenv:coverage] +description = get a test coverage report +use_develop = true +skip_install = false +constrain_package_deps = true +set_env = + ROBOT_BROWSER=headlesschrome + +## +# Specify extra test environment variables in .meta.toml: +# [tox] +# test_environment_variables = """ +# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ +# """ +## +deps = + coverage + zope.testrunner + -c https://dist.plone.org/release/6.0-dev/constraints.txt + +commands = + coverage run --branch --source pas.plugins.passwordstrength {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s pas.plugins.passwordstrength {posargs} + coverage report -m --format markdown + coverage xml +extras = + test -[testenv:py310-lint] -basepython = python3.10 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -allowlist_externals = {[lint]allowlist_externals} -[testenv:docs] +[testenv:release-check] +description = ensure that the distribution is ready to release skip_install = true - deps = - Sphinx - + twine + build + -c https://dist.plone.org/release/6.0-dev/constraints.txt + +commands = + python -m build --sdist + twine check dist/* + +[testenv:circular] +description = ensure there are no cyclic dependencies +use_develop = true +skip_install = false +set_env = + +## +# Specify extra test environment variables in .meta.toml: +# [tox] +# test_environment_variables = """ +# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ +# """ +## +allowlist_externals = + sh +deps = + pipdeptree + pipforester + -c https://dist.plone.org/release/6.0-dev/constraints.txt + commands = - sphinx-build -b html -d _build/docs/doctrees docs _build/docs/html + # Generate the full dependency tree + sh -c 'pipdeptree -j > forest.json' + # Generate a DOT graph with the circular dependencies, if any + pipforester -i forest.json -o forest.dot --cycles + # Report if there are any circular dependencies, i.e. error if there are any + pipforester -i forest.json --check-cycles -o /dev/null + + +## +# Add extra configuration options in .meta.toml: +# [tox] +# extra_lines = """ +# _your own configuration lines_ +# """ +## From f0174b003db63cfbeb8fefb46a6b11ab9603b9c9 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Sun, 26 Nov 2023 23:40:12 +0100 Subject: [PATCH 02/11] versions --- setup.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index fec323f..621d2da 100644 --- a/setup.py +++ b/setup.py @@ -24,12 +24,12 @@ "Environment :: Web Environment", "Framework :: Plone", "Framework :: Plone :: Addon", - "Framework :: Plone :: 5.2", "Framework :: Plone :: 6.0", "Programming Language :: Python", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Operating System :: OS Independent", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", ], @@ -69,7 +69,5 @@ entry_points=""" [z3c.autoinclude.plugin] target = plone - [console_scripts] - update_locale = pas.plugins.passwordstrength.locales.update:update_locale """, ) From f905ac11cfea165b5333d64f00804b388cfb07c6 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Sun, 26 Nov 2023 23:41:47 +0100 Subject: [PATCH 03/11] ci --- .github/workflows/plone-package.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/plone-package.yml b/.github/workflows/plone-package.yml index 9cc2434..c57f013 100644 --- a/.github/workflows/plone-package.yml +++ b/.github/workflows/plone-package.yml @@ -16,9 +16,8 @@ jobs: fail-fast: false matrix: plone-version: - - 'Plone52' - 'Plone60' - python-version: [3.7, 3.8, 3.9] + python-version: [3.8, 3.9, 3.10, 3.11] steps: - uses: actions/setup-python@v4 @@ -62,4 +61,4 @@ jobs: uses: "codecov/codecov-action@v3" with: fail_ci_if_error: true - if: matrix.python-version == '3.7' + if: matrix.python-version == '3.8' From efc8cbcb72553a13c4df119473b9ffab56d57b17 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Sun, 26 Nov 2023 23:49:08 +0100 Subject: [PATCH 04/11] black --- MANIFEST.in | 24 +- README.md | 9 +- docs/conf.py | 238 ------------------ docs/index.rst | 5 - setup.py | 8 +- src/pas/__init__.py | 1 - src/pas/plugins/__init__.py | 1 - src/pas/plugins/passwordstrength/__init__.py | 1 - .../passwordstrength/browser/configure.zcml | 10 +- .../plugins/passwordstrength/configure.zcml | 7 +- .../plugins/passwordstrength/interfaces.py | 1 - .../passwordstrength/locales/update.py | 6 +- .../plugins/passwordstrength/permissions.zcml | 9 +- src/pas/plugins/passwordstrength/plugins.py | 1 - .../profiles/default/browserlayer.xml | 9 +- .../profiles/default/catalog.xml | 2 +- .../profiles/default/metadata.xml | 2 +- .../profiles/default/registry/main.xml | 10 +- .../profiles/default/rolemap.xml | 4 +- .../profiles/uninstall/browserlayer.xml | 9 +- .../plugins/passwordstrength/setuphandlers.py | 3 +- src/pas/plugins/passwordstrength/testing.py | 1 - .../passwordstrength/tests/test_setup.py | 1 - 23 files changed, 64 insertions(+), 298 deletions(-) delete mode 100644 docs/conf.py delete mode 100644 docs/index.rst diff --git a/MANIFEST.in b/MANIFEST.in index 1bf12fd..08d2485 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,19 @@ -graft src/pas.plugins -graft docs +include .coveragerc +include base.cfg +include bobtemplate.cfg +include buildout.cfg +include test_plone52.cfg +include test_plone60.cfg include *.md -exclude tox.ini -exclude *.txt -exclude .gitlab-ci.yml -global-exclude *.pyc +include *.txt +include *.yml +recursive-include docs *.py +recursive-include docs *.rst +recursive-include src *.gitkeep +recursive-include src *.po +recursive-include src *.pot +recursive-include src *.robot +recursive-include src *.rst +recursive-include src *.sh +recursive-include src *.xml +recursive-include src *.zcml diff --git a/README.md b/README.md index 19c8405..c30c456 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,13 @@ Adds verification rules for user passwords in plone. ## Features -- Can be bullet points +## TODO -Evaluate libraries like -or for password strength +* [ ] evaluate libraries like + or for password strength, +* [ ] avoid password reuse, memoizing last password hashes, +* [ ] manage password expire +* [ ] force password reset ## Examples diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 83031fe..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,238 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -source_suffix = ['.rst', '.md'] - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'pas.plugins.passwordstrength' -copyright = u'Mauro Amico (mamico)' -author = u'Mauro Amico (mamico)' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'3.0' -# The full version, including alpha/beta/rc tags. -release = u'3.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. -# " v documentation" by default. -#html_title = u'bobtemplates.plone v3.0' - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (relative to this directory) to use as a favicon of -# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not None, a 'Last updated on:' timestamp is inserted at every page -# bottom, using the given strftime format. -# The empty string is equivalent to '%b %d, %Y'. -#html_last_updated_fmt = None - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Language to be used for generating the HTML full-text search index. -# Sphinx supports the following languages: -# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' -# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' -#html_search_language = 'en' - -# A dictionary with options for the search language support, empty by default. -# 'ja' uses this config value. -# 'zh' user can custom change `jieba` dictionary path. -#html_search_options = {'type': 'default'} - -# The name of a javascript file (relative to the configuration directory) that -# implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'pas.plugins.passwordstrengthdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', - -# Latex figure (float) alignment -#'figure_align': 'htbp', -} - - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index e4989db..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================ -pas.plugins.passwordstrength -============================ - -User documentation diff --git a/setup.py b/setup.py index 621d2da..e73634c 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Installer for the pas.plugins.passwordstrength package.""" from setuptools import find_packages @@ -21,6 +20,7 @@ long_description=long_description, # Get more from https://pypi.org/classifiers/ classifiers=[ + "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Plone", "Framework :: Plone :: Addon", @@ -49,13 +49,13 @@ package_dir={"": "src"}, include_package_data=True, zip_safe=False, - python_requires=">=3.7", + python_requires=">=3.8", install_requires=[ "setuptools", # -*- Extra requirements: -*- "z3c.jbot", "plone.api>=1.8.4", - "plone.app.dexterity", + "plone.base", ], extras_require={ "test": [ @@ -64,7 +64,7 @@ # Remove if your package shall be part of coredev. # plone_coredev tests as of 2016-04-01. "plone.testing>=5.0.0", - ], + ], }, entry_points=""" [z3c.autoinclude.plugin] diff --git a/src/pas/__init__.py b/src/pas/__init__.py index 03d08ff..5284146 100644 --- a/src/pas/__init__.py +++ b/src/pas/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- __import__("pkg_resources").declare_namespace(__name__) diff --git a/src/pas/plugins/__init__.py b/src/pas/plugins/__init__.py index 03d08ff..5284146 100644 --- a/src/pas/plugins/__init__.py +++ b/src/pas/plugins/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- __import__("pkg_resources").declare_namespace(__name__) diff --git a/src/pas/plugins/passwordstrength/__init__.py b/src/pas/plugins/passwordstrength/__init__.py index 8287208..7b1e7ec 100644 --- a/src/pas/plugins/passwordstrength/__init__.py +++ b/src/pas/plugins/passwordstrength/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Init and utils.""" from zope.i18nmessageid import MessageFactory diff --git a/src/pas/plugins/passwordstrength/browser/configure.zcml b/src/pas/plugins/passwordstrength/browser/configure.zcml index 7819c93..66f4093 100644 --- a/src/pas/plugins/passwordstrength/browser/configure.zcml +++ b/src/pas/plugins/passwordstrength/browser/configure.zcml @@ -2,10 +2,14 @@ xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser" xmlns:plone="http://namespaces.plone.org/plone" - i18n_domain="pas.plugins.passwordstrength"> + i18n_domain="pas.plugins.passwordstrength" + > - + diff --git a/src/pas/plugins/passwordstrength/configure.zcml b/src/pas/plugins/passwordstrength/configure.zcml index b422678..1a87177 100644 --- a/src/pas/plugins/passwordstrength/configure.zcml +++ b/src/pas/plugins/passwordstrength/configure.zcml @@ -3,7 +3,8 @@ xmlns:genericsetup="http://namespaces.zope.org/genericsetup" xmlns:i18n="http://namespaces.zope.org/i18n" xmlns:plone="http://namespaces.plone.org/plone" - i18n_domain="pas.plugins.passwordstrength"> + i18n_domain="pas.plugins.passwordstrength" + > @@ -21,18 +22,18 @@ diff --git a/src/pas/plugins/passwordstrength/interfaces.py b/src/pas/plugins/passwordstrength/interfaces.py index 57e516f..d9bca29 100644 --- a/src/pas/plugins/passwordstrength/interfaces.py +++ b/src/pas/plugins/passwordstrength/interfaces.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Module where all interfaces, events and exceptions live.""" from zope.publisher.interfaces.browser import IDefaultBrowserLayer diff --git a/src/pas/plugins/passwordstrength/locales/update.py b/src/pas/plugins/passwordstrength/locales/update.py index 89e03a4..2cf6f6a 100644 --- a/src/pas/plugins/passwordstrength/locales/update.py +++ b/src/pas/plugins/passwordstrength/locales/update.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import os import pkg_resources import subprocess @@ -26,7 +24,7 @@ def locale_folder_setup(): else: lc_messages_path = lang + "/LC_MESSAGES/" os.mkdir(lc_messages_path) - cmd = "msginit --locale={0} --input={1}.pot --output={2}/LC_MESSAGES/{3}.po".format( # NOQA: E501 + cmd = "msginit --locale={} --input={}.pot --output={}/LC_MESSAGES/{}.po".format( # NOQA: E501 lang, domain, lang, @@ -55,7 +53,7 @@ def _rebuild(): def _sync(): - cmd = "{0} sync --pot {1}/{2}.pot {3}*/LC_MESSAGES/{4}.po".format( + cmd = "{} sync --pot {}/{}.pot {}*/LC_MESSAGES/{}.po".format( i18ndude, locale_path, domain, diff --git a/src/pas/plugins/passwordstrength/permissions.zcml b/src/pas/plugins/passwordstrength/permissions.zcml index 1f79c8a..74de0f4 100644 --- a/src/pas/plugins/passwordstrength/permissions.zcml +++ b/src/pas/plugins/passwordstrength/permissions.zcml @@ -1,10 +1,11 @@ + xmlns="http://namespaces.zope.org/zope" + xmlns:zcml="http://namespaces.zope.org/zcml" + i18n_domain="plone" + > - + diff --git a/src/pas/plugins/passwordstrength/plugins.py b/src/pas/plugins/passwordstrength/plugins.py index b91ad56..d4d0bb5 100644 --- a/src/pas/plugins/passwordstrength/plugins.py +++ b/src/pas/plugins/passwordstrength/plugins.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.class_init import InitializeClass from OFS.Cache import Cacheable diff --git a/src/pas/plugins/passwordstrength/profiles/default/browserlayer.xml b/src/pas/plugins/passwordstrength/profiles/default/browserlayer.xml index 726a6c7..72e72d2 100644 --- a/src/pas/plugins/passwordstrength/profiles/default/browserlayer.xml +++ b/src/pas/plugins/passwordstrength/profiles/default/browserlayer.xml @@ -1,7 +1,6 @@ - + - + diff --git a/src/pas/plugins/passwordstrength/profiles/default/catalog.xml b/src/pas/plugins/passwordstrength/profiles/default/catalog.xml index 0685c9d..de5f459 100644 --- a/src/pas/plugins/passwordstrength/profiles/default/catalog.xml +++ b/src/pas/plugins/passwordstrength/profiles/default/catalog.xml @@ -1,4 +1,4 @@ - + diff --git a/src/pas/plugins/passwordstrength/profiles/default/metadata.xml b/src/pas/plugins/passwordstrength/profiles/default/metadata.xml index 3fcf1da..d5bd84a 100644 --- a/src/pas/plugins/passwordstrength/profiles/default/metadata.xml +++ b/src/pas/plugins/passwordstrength/profiles/default/metadata.xml @@ -1,4 +1,4 @@ - + 1000 diff --git a/src/pas/plugins/passwordstrength/profiles/default/registry/main.xml b/src/pas/plugins/passwordstrength/profiles/default/registry/main.xml index 3b8b7fc..46b834a 100644 --- a/src/pas/plugins/passwordstrength/profiles/default/registry/main.xml +++ b/src/pas/plugins/passwordstrength/profiles/default/registry/main.xml @@ -1,8 +1,8 @@ - - + + - + diff --git a/src/pas/plugins/passwordstrength/profiles/default/rolemap.xml b/src/pas/plugins/passwordstrength/profiles/default/rolemap.xml index 0a24e7e..ac7676e 100644 --- a/src/pas/plugins/passwordstrength/profiles/default/rolemap.xml +++ b/src/pas/plugins/passwordstrength/profiles/default/rolemap.xml @@ -1,7 +1,7 @@ - + - + diff --git a/src/pas/plugins/passwordstrength/profiles/uninstall/browserlayer.xml b/src/pas/plugins/passwordstrength/profiles/uninstall/browserlayer.xml index e46fe6e..b3b95d7 100644 --- a/src/pas/plugins/passwordstrength/profiles/uninstall/browserlayer.xml +++ b/src/pas/plugins/passwordstrength/profiles/uninstall/browserlayer.xml @@ -1,7 +1,6 @@ - + - + diff --git a/src/pas/plugins/passwordstrength/setuphandlers.py b/src/pas/plugins/passwordstrength/setuphandlers.py index 9960b70..df9dac0 100644 --- a/src/pas/plugins/passwordstrength/setuphandlers.py +++ b/src/pas/plugins/passwordstrength/setuphandlers.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from pas.plugins.passwordstrength import logger from pas.plugins.passwordstrength import PLUGIN_ID from pas.plugins.passwordstrength.plugins import PasswordStrength @@ -8,7 +7,7 @@ @implementer(INonInstallable) -class HiddenProfiles(object): +class HiddenProfiles: def getNonInstallableProfiles(self): """Hide uninstall profile from site-creation and quickinstaller.""" return [ diff --git a/src/pas/plugins/passwordstrength/testing.py b/src/pas/plugins/passwordstrength/testing.py index d916746..b1d612e 100644 --- a/src/pas/plugins/passwordstrength/testing.py +++ b/src/pas/plugins/passwordstrength/testing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE from plone.app.testing import applyProfile from plone.app.testing import FunctionalTesting diff --git a/src/pas/plugins/passwordstrength/tests/test_setup.py b/src/pas/plugins/passwordstrength/tests/test_setup.py index fec6802..0083dff 100644 --- a/src/pas/plugins/passwordstrength/tests/test_setup.py +++ b/src/pas/plugins/passwordstrength/tests/test_setup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Setup tests for this package.""" from pas.plugins.passwordstrength.testing import ( # noqa: E501 PAS_PLUGINS_PASSWORDSTRENGTH_INTEGRATION_TESTING, From d3ef1905d8e5d7348b3705766f8f795f91ec76ea Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Sun, 26 Nov 2023 23:50:40 +0100 Subject: [PATCH 05/11] ci --- .github/workflows/plone-package.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/plone-package.yml b/.github/workflows/plone-package.yml index c57f013..f6c8044 100644 --- a/.github/workflows/plone-package.yml +++ b/.github/workflows/plone-package.yml @@ -17,7 +17,11 @@ jobs: matrix: plone-version: - 'Plone60' - python-version: [3.8, 3.9, 3.10, 3.11] + python-version: + - 3.8 + - 3.9 + - '3.10' + - '3.11' steps: - uses: actions/setup-python@v4 From 5af729bbe0fe7dd860fbf7bf6681691f0247eb67 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Sun, 26 Nov 2023 23:53:30 +0100 Subject: [PATCH 06/11] ci --- .github/workflows/plone-package.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/plone-package.yml b/.github/workflows/plone-package.yml index f6c8044..39f2ec2 100644 --- a/.github/workflows/plone-package.yml +++ b/.github/workflows/plone-package.yml @@ -52,9 +52,9 @@ jobs: run: | python -m pip install --upgrade pip pip install tox tox-gh-actions - - name: Black-Check - run: | - tox -r -e black-check + # - name: Black-Check + # run: | + # tox -r -e black-check - name: Test with tox run: | tox -r From 21ece5fad4618f26dec8005e6ecb97d3b4796fcf Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Mon, 27 Nov 2023 00:10:41 +0100 Subject: [PATCH 07/11] ci --- .coveragerc | 5 +- .github/dependabot.yml | 6 ++ .github/workflows/plone-package.yml | 68 ------------- MANIFEST.in | 2 - Makefile | 145 ++++++++++++++++++++++++++++ instance.yaml | 8 ++ mx.ini | 15 +++ news/.changelog_template.jinja | 15 +++ news/.gitkeep | 0 pyproject.toml | 54 ++++++++++- setup.py | 23 +++-- tox.ini | 53 +++++----- 12 files changed, 292 insertions(+), 102 deletions(-) create mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/plone-package.yml create mode 100644 Makefile create mode 100644 instance.yaml create mode 100644 mx.ini create mode 100644 news/.changelog_template.jinja create mode 100644 news/.gitkeep diff --git a/.coveragerc b/.coveragerc index 8debd18..ecfad5d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,6 +1,9 @@ +[run] +relative_files = True + [report] include = - src/pas.plugins/* + */src/pas/* omit = */test* */upgrades/* diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6a7695c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/plone-package.yml b/.github/workflows/plone-package.yml deleted file mode 100644 index 39f2ec2..0000000 --- a/.github/workflows/plone-package.yml +++ /dev/null @@ -1,68 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Plone package - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - plone-version: - - 'Plone60' - python-version: - - 3.8 - - 3.9 - - '3.10' - - '3.11' - - steps: - - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - uses: actions/checkout@v3 - - uses: actions/cache@v3 - with: - path: | - ~/.cache/pip - ~/buildout-cache - ~/extends - key: ${{ runner.os }}-tox-${{ matrix.python-version }}-${{ matrix.plone-version }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('**/*.cfg') }}-${{ hashFiles('**/constraints.txt') }}-${{ hashFiles('**/tox.ini') }} - #restore-keys: | - # ${{ runner.os }}-tox- - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: setup buildout cache - run: | - mkdir -p ~/buildout-cache/{eggs,downloads} - mkdir ~/.buildout - echo "[buildout]" > $HOME/.buildout/default.cfg - echo "download-cache = $HOME/buildout-cache/downloads" >> $HOME/.buildout/default.cfg - echo "eggs-directory = $HOME/buildout-cache/eggs" >> $HOME/.buildout/default.cfg - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install tox tox-gh-actions - # - name: Black-Check - # run: | - # tox -r -e black-check - - name: Test with tox - run: | - tox -r - env: - PLONE-VERSION: ${{ matrix.plone-version }} - PYTHON-VERSION: ${{ matrix.python-version }} - - name: "Upload coverage to Codecov" - uses: "codecov/codecov-action@v3" - with: - fail_ci_if_error: true - if: matrix.python-version == '3.8' diff --git a/MANIFEST.in b/MANIFEST.in index 08d2485..f74cb18 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,8 +7,6 @@ include test_plone60.cfg include *.md include *.txt include *.yml -recursive-include docs *.py -recursive-include docs *.rst recursive-include src *.gitkeep recursive-include src *.po recursive-include src *.pot diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0a07d98 --- /dev/null +++ b/Makefile @@ -0,0 +1,145 @@ +### Defensive settings for make: +# https://tech.davis-hansson.com/p/make/ +SHELL:=bash +.ONESHELL: +.SHELLFLAGS:=-xeu -o pipefail -O inherit_errexit -c +.SILENT: +.DELETE_ON_ERROR: +MAKEFLAGS+=--warn-undefined-variables +MAKEFLAGS+=--no-builtin-rules + +# We like colors +# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects +RED=`tput setaf 1` +GREEN=`tput setaf 2` +RESET=`tput sgr0` +YELLOW=`tput setaf 3` + +BACKEND_FOLDER=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +COMPOSE_FOLDER=${BACKEND_FOLDER}/tests +DOCS_DIR=${BACKEND_FOLDER}/docs + +# Python checks +PYTHON?=python3 + +# installed? +ifeq (, $(shell which $(PYTHON) )) + $(error "PYTHON=$(PYTHON) not found in $(PATH)") +endif + +# version ok? +PYTHON_VERSION_MIN=3.8 +PYTHON_VERSION_OK=$(shell $(PYTHON) -c "import sys; print((int(sys.version_info[0]), int(sys.version_info[1])) >= tuple(map(int, '$(PYTHON_VERSION_MIN)'.split('.'))))") +ifeq ($(PYTHON_VERSION_OK),0) + $(error "Need python $(PYTHON_VERSION) >= $(PYTHON_VERSION_MIN)") +endif + +all: build + +# Add the following 'help' target to your Makefile +# And add help text after each target name starting with '\#\#' +.PHONY: help +help: ## This help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: clean +clean: clean-build clean-pyc clean-test clean-venv clean-instance ## remove all build, test, coverage and Python artifacts + +.PHONY: clean-instance +clean-instance: ## remove existing instance + rm -fr instance etc inituser var + +.PHONY: clean-venv +clean-venv: ## remove virtual environment + rm -fr bin include lib lib64 env pyvenv.cfg .tox .pytest_cache requirements-mxdev.txt + +.PHONY: clean-build +clean-build: ## remove build artifacts + rm -fr build/ + rm -fr dist/ + rm -fr .eggs/ + find . -name '*.egg-info' -exec rm -fr {} + + find . -name '*.egg' -exec rm -rf {} + + +.PHONY: clean-pyc +clean-pyc: ## remove Python file artifacts + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -fr {} + + +.PHONY: clean-test +clean-test: ## remove test and coverage artifacts + rm -f .coverage + rm -fr htmlcov/ + +bin/pip bin/tox bin/mxdev: + @echo "$(GREEN)==> Setup Virtual Env$(RESET)" + $(PYTHON) -m venv . + bin/pip install -U "pip" "wheel" "cookiecutter" "mxdev" "tox" + +.PHONY: config +config: bin/pip ## Create instance configuration + @echo "$(GREEN)==> Create instance configuration$(RESET)" + bin/cookiecutter -f --no-input --config-file instance.yaml gh:plone/cookiecutter-zope-instance + +.PHONY: install-plone-6.0 +install-plone-6.0: config ## pip install Plone packages + @echo "$(GREEN)==> Setup Build$(RESET)" + bin/mxdev -c mx.ini + bin/pip install -r requirements-mxdev.txt + +.PHONY: install +install: install-plone-6.0 ## Install Plone 6.0 + +.PHONY: start +start: ## Start a Plone instance on localhost:8080 + PYTHONWARNINGS=ignore ./bin/runwsgi instance/etc/zope.ini + +.PHONY: console +console: ## Console + PYTHONWARNINGS=ignore ./bin/zconsole debug instance/etc/zope.ini + +.PHONY: format +format: bin/tox ## Format the codebase according to our standards + @echo "$(GREEN)==> Format codebase$(RESET)" + bin/tox -e format + +.PHONY: lint +lint: bin/tox ## check code style + bin/tox -e lint + +# i18n +bin/i18ndude bin/pocompile: bin/pip + @echo "$(GREEN)==> Install translation tools$(RESET)" + bin/pip install i18ndude zest.pocompile + +.PHONY: i18n +i18n: bin/i18ndude ## Update locales + @echo "$(GREEN)==> Updating locales$(RESET)" + bin/update_locale + bin/pocompile src/ + +# Tests +.PHONY: test +test: bin/tox ## run tests + bin/tox -e test + +.PHONY: test-coverage +test-coverage: bin/tox ## run tests + bin/tox -e coverage + +# Docs +bin/sphinx-build: bin/pip + bin/pip install -r requirements-docs.txt + +.PHONY: build-docs +build-docs: bin/sphinx-build ## Build the documentation + ./bin/sphinx-build \ + -b html $(DOCS_DIR) "$(DOCS_DIR)/_build/html" + +.PHONY: livehtml +livehtml: bin/sphinx-build ## Rebuild Sphinx documentation on changes, with live-reload in the browser + ./bin/sphinx-autobuild \ + --ignore "*.swp" \ + -b html $(DOCS_DIR) "$(DOCS_DIR)/_build/html" diff --git a/instance.yaml b/instance.yaml new file mode 100644 index 0000000..1df1049 --- /dev/null +++ b/instance.yaml @@ -0,0 +1,8 @@ +default_context: + initial_user_name: 'admin' + initial_user_password: 'admin' + + load_zcml: + package_includes: ['pas.plugins.passwordstrength'] + + db_storage: direct diff --git a/mx.ini b/mx.ini new file mode 100644 index 0000000..6e7929c --- /dev/null +++ b/mx.ini @@ -0,0 +1,15 @@ +; This is a mxdev configuration file +; it can be used to override versions of packages already defined in the +; constraints files and to add new packages from VCS like git. +; to learn more about mxdev visit https://pypi.org/project/mxdev/ + +[settings] +version-overrides = + plone.restapi>=8.40.0 + +; example section to use packages from git +; [example.contenttype] +; url = https://github.com/collective/example.contenttype.git +; pushurl = git@github.com:collective/example.contenttype.git +; extras = test +; branch = feature-7 diff --git a/news/.changelog_template.jinja b/news/.changelog_template.jinja new file mode 100644 index 0000000..b35bff3 --- /dev/null +++ b/news/.changelog_template.jinja @@ -0,0 +1,15 @@ +{% if sections[""] %} +{% for category, val in definitions.items() if category in sections[""] %} + +### {{ definitions[category]['name'] }} + +{% for text, values in sections[""][category].items() %} +- {{ text }} {{ values|join(', ') }} +{% endfor %} + +{% endfor %} +{% else %} +No significant changes. + + +{% endif %} \ No newline at end of file diff --git a/news/.gitkeep b/news/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index 1605056..851cf49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,6 +4,45 @@ [build-system] requires = ["setuptools>=68.2"] +[tool.towncrier] +directory = "news/" +filename = "CHANGES.md" +start_string = "\n" +title_format = "## {version} ({project_date})" +template = "news/.changelog_template.jinja" +underlines = ["", "", ""] +issue_format = "[#{issue}](https://github.com/collective/pas.plugins.oidc/issues/{issue})" + +[[tool.towncrier.type]] +directory = "breaking" +name = "Breaking changes:" +showcontent = true + +[[tool.towncrier.type]] +directory = "feature" +name = "New features:" +showcontent = true + +[[tool.towncrier.type]] +directory = "bugfix" +name = "Bug fixes:" +showcontent = true + +[[tool.towncrier.type]] +directory = "internal" +name = "Internal:" +showcontent = true + +[[tool.towncrier.type]] +directory = "documentation" +name = "Documentation:" +showcontent = true + +[[tool.towncrier.type]] +directory = "tests" +name = "Tests" +showcontent = true + ## # Add extra configuration options in .meta.toml: # [pyproject] @@ -35,8 +74,8 @@ target-version = ["py38"] ## [tool.codespell] -ignore-words-list = "discreet," -skip = "*.po," +ignore-words-list = "discreet,vew" +skip = "*.po,*.min.js,*.pot,*.po,*.yaml,*.json" ## # Add extra configuration options in .meta.toml: # [pyproject] @@ -83,6 +122,8 @@ Zope = [ 'Products.CMFCore', 'Products.CMFDynamicViewFTI', ] python-dateutil = ['dateutil'] +ignore-packages = ['plone.restapi', 'plone.volto', 'zestreleaser.towncrier', 'zest.releaser', 'pytest', 'pytest-cov', 'pytest-plone', 'pytest-docker', 'pytest-vcr', 'pytest-mock', 'gocept.pytestlayer', 'requests-mock', 'vcrpy'] +Plone = ['Products.CMFPlone', 'Products.CMFCore', 'Products.GenericSetup', 'Products.PluggableAuthService', 'Products.PlonePAS'] ## # Add extra configuration options in .meta.toml: @@ -102,6 +143,9 @@ ignore = [ "tox.ini", ".flake8", "mx.ini", + "news/*", + "constraints-mxdev.txt", + "requirements-mxdev.txt", ] ## @@ -113,6 +157,12 @@ ignore = [ # """ ## +[tool.coverage.run] +omit = ["*/locales/*"] + +[tool.bandit] +targets = "src" +exclude_dirs = ["tests", "src/pas/plugins/oidc/locales"] ## # Add extra configuration options in .meta.toml: diff --git a/setup.py b/setup.py index e73634c..37af00f 100644 --- a/setup.py +++ b/setup.py @@ -52,18 +52,27 @@ python_requires=">=3.8", install_requires=[ "setuptools", - # -*- Extra requirements: -*- + "Plone", + "plone.api", + "plone.restapi>=8.34.0", "z3c.jbot", - "plone.api>=1.8.4", - "plone.base", ], extras_require={ "test": [ + # "plone.app.testing", + # "plone.testing>=5.0.0", + "gocept.pytestlayer", "plone.app.testing", - # Plone KGS does not use this version, because it would break - # Remove if your package shall be part of coredev. - # plone_coredev tests as of 2016-04-01. - "plone.testing>=5.0.0", + "plone.restapi[test]", + "pytest-cov", + "pytest-plone>=0.2.0", + "pytest-docker", + "pytest-mock", + "pytest", + "zest.releaser[recommended]", + "zestreleaser.towncrier", + "pytest-mock", + "requests-mock", ], }, entry_points=""" diff --git a/tox.ini b/tox.ini index 81c356d..3724172 100644 --- a/tox.ini +++ b/tox.ini @@ -43,8 +43,11 @@ commands = [testenv:init] description = Prepare environment skip_install = true +deps = + mxdev commands = - echo "Initial setup complete" + mxdev -c mx.ini + echo "Initial setup for mxdev" [testenv:format] @@ -91,7 +94,7 @@ commands = description = run the distribution tests use_develop = true skip_install = false -constrain_package_deps = true +constrain_package_deps = false set_env = ROBOT_BROWSER=headlesschrome @@ -104,40 +107,36 @@ set_env = # # Set constrain_package_deps .meta.toml: # [tox] -# constrain_package_deps = "false" +# constrain_package_deps = false ## deps = - zope.testrunner - -c https://dist.plone.org/release/6.0-dev/constraints.txt - + pytest-plone + pytest + -c constraints-mxdev.txt + + ## # Specify additional deps in .meta.toml: # [tox] -# test_deps_additional = "-esources/plonegovbr.portal_base[test]" +# test_deps_additional = """ +# -esources/plonegovbr.portal_base[test] +# """ # # Specify a custom constraints file in .meta.toml: # [tox] # constraints_file = "https://my-server.com/constraints.txt" ## commands = - zope-testrunner --all --test-path={toxinidir}/src -s pas.plugins.passwordstrength {posargs} + pytest --disable-warnings {posargs} {toxinidir}/tests extras = test -## -# Add extra configuration options in .meta.toml: -# [tox] -# test_extras = """ -# tests -# widgets -# """ -## [testenv:coverage] description = get a test coverage report use_develop = true skip_install = false -constrain_package_deps = true +constrain_package_deps = false set_env = ROBOT_BROWSER=headlesschrome @@ -147,14 +146,19 @@ set_env = # test_environment_variables = """ # PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ # """ +# +# Set constrain_package_deps .meta.toml: +# [tox] +# constrain_package_deps = "false" ## deps = + pytest-plone + pytest coverage - zope.testrunner - -c https://dist.plone.org/release/6.0-dev/constraints.txt + -c constraints-mxdev.txt commands = - coverage run --branch --source pas.plugins.passwordstrength {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s pas.plugins.passwordstrength {posargs} + coverage run --source pas.plugins.oidc -m pytest {posargs} --disable-warnings {toxinidir}/tests coverage report -m --format markdown coverage xml extras = @@ -167,9 +171,14 @@ skip_install = true deps = twine build - -c https://dist.plone.org/release/6.0-dev/constraints.txt + towncrier + -c constraints-mxdev.txt commands = + # fake version to not have to install the package + # we build the change log as news entries might break + # the README that is displayed on PyPI + towncrier build --version=100.0.0 --yes python -m build --sdist twine check dist/* @@ -191,7 +200,7 @@ allowlist_externals = deps = pipdeptree pipforester - -c https://dist.plone.org/release/6.0-dev/constraints.txt + -c constraints-mxdev.txt commands = # Generate the full dependency tree From d7b6b1e6ee66f33216706b698cdc4c29324cc85c Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Mon, 27 Nov 2023 00:36:58 +0100 Subject: [PATCH 08/11] pytests --- MANIFEST.in | 24 +++--- pyproject.toml | 4 +- src/pas/plugins/passwordstrength/testing.py | 33 +++----- .../passwordstrength/tests/__init__.py | 0 .../tests/robot/test_example.robot | 66 --------------- .../passwordstrength/tests/test_setup.py | 74 ----------------- tests/conftest.py | 70 ++++++++++++++++ tests/docker-compose.yml | 41 ++++++++++ tests/functional/conftest.py | 69 ++++++++++++++++ tests/functional/test_functional.py | 13 +++ tests/plugin/test_plugin.py | 24 ++++++ tests/services/conftest.py | 81 +++++++++++++++++++ tests/services/test_services_login_get.py | 28 +++++++ tests/setup/test_setup_install.py | 41 ++++++++++ tests/setup/test_setup_uninstall.py | 29 +++++++ tox.ini | 2 +- 16 files changed, 423 insertions(+), 176 deletions(-) delete mode 100644 src/pas/plugins/passwordstrength/tests/__init__.py delete mode 100644 src/pas/plugins/passwordstrength/tests/robot/test_example.robot delete mode 100644 src/pas/plugins/passwordstrength/tests/test_setup.py create mode 100644 tests/conftest.py create mode 100644 tests/docker-compose.yml create mode 100644 tests/functional/conftest.py create mode 100644 tests/functional/test_functional.py create mode 100644 tests/plugin/test_plugin.py create mode 100644 tests/services/conftest.py create mode 100644 tests/services/test_services_login_get.py create mode 100644 tests/setup/test_setup_install.py create mode 100644 tests/setup/test_setup_uninstall.py diff --git a/MANIFEST.in b/MANIFEST.in index f74cb18..c49a22d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,17 +1,19 @@ +graft src/pas +graft docs +global-exclude *.pyc +include *.md +include *.txt +include *.yaml include .coveragerc +include Makefile +recursive-include tests *.py +recursive-include tests *.gitkeep +recursive-include tests *.json +recursive-include tests *.yml +# -- +include *.yml include base.cfg include bobtemplate.cfg include buildout.cfg include test_plone52.cfg include test_plone60.cfg -include *.md -include *.txt -include *.yml -recursive-include src *.gitkeep -recursive-include src *.po -recursive-include src *.pot -recursive-include src *.robot -recursive-include src *.rst -recursive-include src *.sh -recursive-include src *.xml -recursive-include src *.zcml diff --git a/pyproject.toml b/pyproject.toml index 851cf49..1329608 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ start_string = "\n" title_format = "## {version} ({project_date})" template = "news/.changelog_template.jinja" underlines = ["", "", ""] -issue_format = "[#{issue}](https://github.com/collective/pas.plugins.oidc/issues/{issue})" +issue_format = "[#{issue}](https://github.com/collective/pas.plugins.passwordstrength/issues/{issue})" [[tool.towncrier.type]] directory = "breaking" @@ -162,7 +162,7 @@ omit = ["*/locales/*"] [tool.bandit] targets = "src" -exclude_dirs = ["tests", "src/pas/plugins/oidc/locales"] +exclude_dirs = ["tests", "src/pas/plugins/passwordstrength/locales"] ## # Add extra configuration options in .meta.toml: diff --git a/src/pas/plugins/passwordstrength/testing.py b/src/pas/plugins/passwordstrength/testing.py index b1d612e..c09b3b5 100644 --- a/src/pas/plugins/passwordstrength/testing.py +++ b/src/pas/plugins/passwordstrength/testing.py @@ -1,53 +1,42 @@ -from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE from plone.app.testing import applyProfile from plone.app.testing import FunctionalTesting from plone.app.testing import IntegrationTesting from plone.app.testing import PLONE_FIXTURE from plone.app.testing import PloneSandboxLayer -from plone.testing import z2 +from plone.testing.zope import WSGI_SERVER_FIXTURE import pas.plugins.passwordstrength -class PasPluginsPasswordstrengthLayer(PloneSandboxLayer): +class TestLayer(PloneSandboxLayer): defaultBases = (PLONE_FIXTURE,) def setUpZope(self, app, configurationContext): # Load any other ZCML that is required for your tests. # The z3c.autoinclude feature is disabled in the Plone fixture base # layer. - import plone.app.dexterity - - self.loadZCML(package=plone.app.dexterity) - import plone.restapi - - self.loadZCML(package=plone.restapi) self.loadZCML(package=pas.plugins.passwordstrength) def setUpPloneSite(self, portal): + applyProfile(portal, "plone.restapi:default") applyProfile(portal, "pas.plugins.passwordstrength:default") -PAS_PLUGINS_PASSWORDSTRENGTH_FIXTURE = PasPluginsPasswordstrengthLayer() +FIXTURE = TestLayer() -PAS_PLUGINS_PASSWORDSTRENGTH_INTEGRATION_TESTING = IntegrationTesting( - bases=(PAS_PLUGINS_PASSWORDSTRENGTH_FIXTURE,), +INTEGRATION_TESTING = IntegrationTesting( + bases=(FIXTURE,), name="PasPluginsPasswordstrengthLayer:IntegrationTesting", ) -PAS_PLUGINS_PASSWORDSTRENGTH_FUNCTIONAL_TESTING = FunctionalTesting( - bases=(PAS_PLUGINS_PASSWORDSTRENGTH_FIXTURE,), +FUNCTIONAL_TESTING = FunctionalTesting( + bases=(FIXTURE,), name="PasPluginsPasswordstrengthLayer:FunctionalTesting", ) - -PAS_PLUGINS_PASSWORDSTRENGTH_ACCEPTANCE_TESTING = FunctionalTesting( - bases=( - PAS_PLUGINS_PASSWORDSTRENGTH_FIXTURE, - REMOTE_LIBRARY_BUNDLE_FIXTURE, - z2.ZSERVER_FIXTURE, - ), - name="PasPluginsPasswordstrengthLayer:AcceptanceTesting", +RESTAPI_TESTING = FunctionalTesting( + bases=(FIXTURE, WSGI_SERVER_FIXTURE), + name="PasPluginsPasswordstrengthLayer:RestAPITesting", ) diff --git a/src/pas/plugins/passwordstrength/tests/__init__.py b/src/pas/plugins/passwordstrength/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/pas/plugins/passwordstrength/tests/robot/test_example.robot b/src/pas/plugins/passwordstrength/tests/robot/test_example.robot deleted file mode 100644 index a25c120..0000000 --- a/src/pas/plugins/passwordstrength/tests/robot/test_example.robot +++ /dev/null @@ -1,66 +0,0 @@ -# ============================================================================ -# EXAMPLE ROBOT TESTS -# ============================================================================ -# -# Run this robot test stand-alone: -# -# $ bin/test -s pas.plugins.passwordstrength -t test_example.robot --all -# -# Run this robot test with robot server (which is faster): -# -# 1) Start robot server: -# -# $ bin/robot-server --reload-path src pas.plugins.passwordstrength.testing.PAS_PLUGINS_PASSWORDSTRENGTH_ACCEPTANCE_TESTING -# -# 2) Run robot tests: -# -# $ bin/robot src/pas/plugins/passwordstrength/tests/robot/test_example.robot -# -# See the http://docs.plone.org for further details (search for robot -# framework). -# -# ============================================================================ - -*** Settings ***************************************************************** - -Resource plone/app/robotframework/selenium.robot -Resource plone/app/robotframework/keywords.robot - -Library Remote ${PLONE_URL}/RobotRemote - -Test Setup Open test browser -Test Teardown Close all browsers - - -*** Test Cases *************************************************************** - -Scenario: As a member I want to be able to log into the website - [Documentation] Example of a BDD-style (Behavior-driven development) test. - Given a login form - When I enter valid credentials - Then I am logged in - - -*** Keywords ***************************************************************** - -# --- Given ------------------------------------------------------------------ - -a login form - Go To ${PLONE_URL}/login_form - Wait until page contains Login Name - Wait until page contains Password - - -# --- WHEN ------------------------------------------------------------------- - -I enter valid credentials - Input Text __ac_name admin - Input Text __ac_password secret - Click Button Log in - - -# --- THEN ------------------------------------------------------------------- - -I am logged in - Wait until page contains You are now logged in - Page should contain You are now logged in diff --git a/src/pas/plugins/passwordstrength/tests/test_setup.py b/src/pas/plugins/passwordstrength/tests/test_setup.py deleted file mode 100644 index 0083dff..0000000 --- a/src/pas/plugins/passwordstrength/tests/test_setup.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Setup tests for this package.""" -from pas.plugins.passwordstrength.testing import ( # noqa: E501 - PAS_PLUGINS_PASSWORDSTRENGTH_INTEGRATION_TESTING, -) -from plone import api -from plone.app.testing import setRoles -from plone.app.testing import TEST_USER_ID - -import unittest - - -try: - from Products.CMFPlone.utils import get_installer -except ImportError: - get_installer = None - - -class TestSetup(unittest.TestCase): - """Test that pas.plugins.passwordstrength is properly installed.""" - - layer = PAS_PLUGINS_PASSWORDSTRENGTH_INTEGRATION_TESTING - - def setUp(self): - """Custom shared utility setup for tests.""" - self.portal = self.layer["portal"] - if get_installer: - self.installer = get_installer(self.portal, self.layer["request"]) - else: - self.installer = api.portal.get_tool("portal_quickinstaller") - - def test_product_installed(self): - """Test if pas.plugins.passwordstrength is installed.""" - self.assertTrue( - self.installer.is_product_installed("pas.plugins.passwordstrength") - ) - - def test_browserlayer(self): - """Test that IPasPluginsPasswordstrengthLayer is registered.""" - from pas.plugins.passwordstrength.interfaces import ( - IPasPluginsPasswordstrengthLayer, - ) - from plone.browserlayer import utils - - self.assertIn(IPasPluginsPasswordstrengthLayer, utils.registered_layers()) - - -class TestUninstall(unittest.TestCase): - layer = PAS_PLUGINS_PASSWORDSTRENGTH_INTEGRATION_TESTING - - def setUp(self): - self.portal = self.layer["portal"] - if get_installer: - self.installer = get_installer(self.portal, self.layer["request"]) - else: - self.installer = api.portal.get_tool("portal_quickinstaller") - roles_before = api.user.get_roles(TEST_USER_ID) - setRoles(self.portal, TEST_USER_ID, ["Manager"]) - self.installer.uninstall_product("pas.plugins.passwordstrength") - setRoles(self.portal, TEST_USER_ID, roles_before) - - def test_product_uninstalled(self): - """Test if pas.plugins.passwordstrength is cleanly uninstalled.""" - self.assertFalse( - self.installer.is_product_installed("pas.plugins.passwordstrength") - ) - - def test_browserlayer_removed(self): - """Test that IPasPluginsPasswordstrengthLayer is removed.""" - from pas.plugins.passwordstrength.interfaces import ( - IPasPluginsPasswordstrengthLayer, - ) - from plone.browserlayer import utils - - self.assertNotIn(IPasPluginsPasswordstrengthLayer, utils.registered_layers()) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..425984f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,70 @@ +from pas.plugins.passwordstrength.testing import FUNCTIONAL_TESTING +from pas.plugins.passwordstrength.testing import INTEGRATION_TESTING +from pas.plugins.passwordstrength.testing import RESTAPI_TESTING +from pathlib import Path +from pytest_plone import fixtures_factory +from requests.exceptions import ConnectionError + +import pytest +import requests + + +pytest_plugins = ["pytest_plone"] + + +globals().update( + fixtures_factory( + ( + (INTEGRATION_TESTING, "integration"), + (FUNCTIONAL_TESTING, "functional"), + (RESTAPI_TESTING, "restapi"), + ) + ) +) + + +@pytest.fixture(scope="session") +def docker_compose_file(pytestconfig): + """Fixture pointing to the docker-compose file to be used.""" + return Path(str(pytestconfig.rootdir)).resolve() / "tests" / "docker-compose.yml" + + +def is_responsive(url: str) -> bool: + try: + response = requests.get(url) + if response.status_code == 200: + return True + except ConnectionError: + return False + + +@pytest.fixture(scope="session") +def keycloak_service(docker_ip, docker_services): + """Ensure that keycloak service is up and responsive.""" + # `port_for` takes a container port and returns the corresponding host port + port = docker_services.port_for("keycloak", 8080) + url = f"http://{docker_ip}:{port}" + docker_services.wait_until_responsive( + timeout=50.0, pause=0.1, check=lambda: is_responsive(url) + ) + return url + + +@pytest.fixture(scope="session") +def keycloak(keycloak_service): + return { + "issuer": f"{keycloak_service}/realms/plone-test", + "client_id": "plone", + "client_secret": "12345678", # nosec B105 + "scope": ("openid", "profile", "email"), + } + + +@pytest.fixture +def wait_for(): + def func(thread): + if not thread: + return + thread.join() + + return func diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml new file mode 100644 index 0000000..bb2a4e8 --- /dev/null +++ b/tests/docker-compose.yml @@ -0,0 +1,41 @@ +version: "3.9" + +services: + keycloak: + build: + context: keycloak + args: + KEYCLOAK_VERSION: 22.0.0 + command: ['start-dev', '--import-realm'] + depends_on: + - db + environment: + JAVA_OPTS_APPEND: -Dkeycloak.profile.feature.upload_scripts=enabled + KC_DB: postgres + KC_DB_PASSWORD: postgres + KC_DB_URL: jdbc:postgresql://db/keycloak + KC_DB_USERNAME: postgres + KC_HEALTH_ENABLED: false + KC_HTTP_ENABLED: true + KC_METRICS_ENABLED: false + KC_HOSTNAME_URL: http://127.0.0.1:8180/ + KC_PROXY: reencrypt + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + volumes: + - ./keycloak/import:/opt/keycloak/data/import + ports: + - 8180:8080 + + db: + image: postgres:14.9 + healthcheck: + test: [ "CMD", "pg_isready", "-q", "-d", "postgres", "-U", "root" ] + timeout: 45s + interval: 5s + retries: 10 + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: keycloak + POSTGRES_HOST: postgres diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py new file mode 100644 index 0000000..7747360 --- /dev/null +++ b/tests/functional/conftest.py @@ -0,0 +1,69 @@ +from plone import api +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_NAME +from plone.app.testing import TEST_USER_PASSWORD +from plone.testing.zope import Browser +from zope.component.hooks import setSite + +import pytest +import transaction + + +@pytest.fixture() +def app(functional): + return functional["app"] + + +@pytest.fixture() +def portal(functional, keycloak): + portal = functional["portal"] + setSite(portal) + plugin = portal.acl_users.passwordstrength + with api.env.adopt_roles(["Manager", "Member"]): + for key, value in keycloak.items(): + setattr(plugin, key, value) + transaction.commit() + yield portal + with api.env.adopt_roles(["Manager", "Member"]): + for key, value in keycloak.items(): + if key != "scope": + value = "" + setattr(plugin, key, value) + transaction.commit() + + +@pytest.fixture() +def http_request(functional): + return functional["request"] + + +@pytest.fixture() +def browser_factory(app): + def factory(): + browser = Browser(app) + browser.handleErrors = False + browser.followRedirects = False + return browser + + return factory + + +@pytest.fixture() +def browser_anonymous(browser_factory): + browser = browser_factory() + return browser + + +@pytest.fixture() +def browser_user(browser_factory): + browser = browser_factory() + browser.addHeader("Authorization", f"Basic {TEST_USER_NAME}:{TEST_USER_PASSWORD}") + return browser + + +@pytest.fixture() +def browser_manager(browser_factory): + browser = browser_factory() + browser.addHeader("Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}") + return browser diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py new file mode 100644 index 0000000..efb2e83 --- /dev/null +++ b/tests/functional/test_functional.py @@ -0,0 +1,13 @@ +from pas.plugins.passwordstrength import PLUGIN_ID +from plone import api + +import pytest + + +class TestFunctionalPlugin: + @pytest.fixture(autouse=True) + def _initialize(self, portal): + pas = api.portal.get_tool("acl_users") + plugin = getattr(pas, PLUGIN_ID) + self.portal_url = api.portal.get().absolute_url() + self.plugin_url = plugin.absolute_url() diff --git a/tests/plugin/test_plugin.py b/tests/plugin/test_plugin.py new file mode 100644 index 0000000..e12d5a2 --- /dev/null +++ b/tests/plugin/test_plugin.py @@ -0,0 +1,24 @@ +from pas.plugins.passwordstrength import PLUGIN_ID +from plone import api + +import pytest + + +class TestPlugin: + @pytest.fixture(autouse=True) + def _initialize(self, portal, http_request): + self.pas = api.portal.get_tool("acl_users") + self.plugin = getattr(self.pas, PLUGIN_ID) + self.http_request = http_request + self.http_response = http_request.response + + @pytest.mark.parametrize( + "property,expected", + [ + ("create_user", True), + ("create_ticket", True), + ], + ) + def test_plugin_setup(self, property, expected): + plugin = self.plugin + assert plugin.getProperty(property) is expected diff --git a/tests/services/conftest.py b/tests/services/conftest.py new file mode 100644 index 0000000..49ba105 --- /dev/null +++ b/tests/services/conftest.py @@ -0,0 +1,81 @@ +from bs4 import BeautifulSoup +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_NAME +from plone.app.testing import TEST_USER_PASSWORD +from plone.restapi.testing import RelativeSession +from urllib.parse import urlparse +from zope.component.hooks import setSite + +import pytest +import requests +import transaction + + +@pytest.fixture() +def app(restapi): + return restapi["app"] + + +@pytest.fixture() +def portal(restapi, keycloak): + portal = restapi["portal"] + setSite(portal) + # plugin = portal.acl_users.passwordstrength_policy + transaction.commit() + + +@pytest.fixture() +def http_request(restapi): + return restapi["request"] + + +@pytest.fixture() +def request_api_factory(portal): + def factory(): + url = portal.absolute_url() + api_session = RelativeSession(f"{url}/++api++") + return api_session + + return factory + + +@pytest.fixture() +def api_anon_request(request_api_factory): + return request_api_factory() + + +@pytest.fixture() +def api_user_request(request_api_factory): + request = request_api_factory() + request.auth = (TEST_USER_NAME, TEST_USER_PASSWORD) + yield request + request.auth = () + + +@pytest.fixture() +def api_manager_request(request_api_factory): + request = request_api_factory() + request.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + yield request + request.auth = () + + +@pytest.fixture() +def keycloak_login(): + def func(url: str): + session = requests.Session() + resp = session.get(url) + soup = BeautifulSoup(resp.content) + data = { + "username": TEST_USER_NAME, + "password": TEST_USER_PASSWORD, + "credentialId": "", + } + next_url = soup.find("form", attrs={"id": "kc-form-login"})["action"] + resp = session.post(next_url, data=data, allow_redirects=False) + location = resp.headers["Location"] + qs = urlparse(location).query + return qs + + return func diff --git a/tests/services/test_services_login_get.py b/tests/services/test_services_login_get.py new file mode 100644 index 0000000..60f9da4 --- /dev/null +++ b/tests/services/test_services_login_get.py @@ -0,0 +1,28 @@ +import pytest + + +class TestServiceLoginGet: + @pytest.fixture(autouse=True) + def _initialize(self, api_anon_request): + self.api_session = api_anon_request + + def test_login_get_available(self): + response = self.api_session.get("@login") + assert response.status_code == 200 + data = response.json() + assert isinstance(data, dict) + + # @pytest.mark.parametrize( + # "idx, key, expected", + # [ + # [0, "id", "oidc"], + # [0, "plugin", "oidc"], + # [0, "url", "/@login-oidc/oidc"], + # [0, "title", "OIDC Authentication"], + # ], + # ) + # def test_login_get_options(self, idx: int, key: str, expected: str): + # response = self.api_session.get("@login") + # data = response.json() + # options = data["options"] + # assert expected in options[idx][key] diff --git a/tests/setup/test_setup_install.py b/tests/setup/test_setup_install.py new file mode 100644 index 0000000..97fa722 --- /dev/null +++ b/tests/setup/test_setup_install.py @@ -0,0 +1,41 @@ +from pas.plugins.passwordstrength import PACKAGE_NAME +from plone import api + +import pytest + + +class TestSetupInstall: + @pytest.fixture(autouse=True) + def _initialize(self, portal): + self.portal = portal + + def test_addon_installed(self, installer): + assert installer.is_product_installed(PACKAGE_NAME) is True + + def test_latest_version(self, profile_last_version): + """Test latest version of default profile.""" + assert profile_last_version(f"{PACKAGE_NAME}:default") == "1001" + + def test_browserlayer(self, browser_layers): + """Test that IPasPluginsPasswordstrengthLayer is registered.""" + from pas.plugins.passwordstrength.interfaces import ( + IPasPluginsPasswordstrengthLayer, + ) + + assert IPasPluginsPasswordstrengthLayer in browser_layers + + def test_plugin_added(self): + """Test if plugin is added to acl_users.""" + from pas.plugins.passwordstrength import PLUGIN_ID + + pas = api.portal.get_tool("acl_users") + assert PLUGIN_ID in pas.objectIds() + + def test_plugin_is_passwordstrength(self): + """Test if we have the correct plugin.""" + from pas.plugins.passwordstrength import PLUGIN_ID + from pas.plugins.passwordstrength.plugins import PasswordStrength + + pas = api.portal.get_tool("acl_users") + plugin = getattr(pas, PLUGIN_ID) + assert isinstance(plugin, PasswordStrength) diff --git a/tests/setup/test_setup_uninstall.py b/tests/setup/test_setup_uninstall.py new file mode 100644 index 0000000..993b708 --- /dev/null +++ b/tests/setup/test_setup_uninstall.py @@ -0,0 +1,29 @@ +from pas.plugins.passwordstrength import PACKAGE_NAME +from plone import api + +import pytest + + +class TestSetupUninstall: + @pytest.fixture(autouse=True) + def uninstalled(self, installer): + installer.uninstall_product(PACKAGE_NAME) + + def test_product_uninstalled(self, installer): + """Test if pas.plugins.passwordstrength is cleanly uninstalled.""" + assert installer.is_product_installed(PACKAGE_NAME) is False + + def test_browserlayer(self, browser_layers): + """Test that IPasPluginsPasswordstrengthLayer is removed.""" + from pas.plugins.passwordstrength.interfaces import ( + IPasPluginsPasswordstrengthLayer, + ) + + assert IPasPluginsPasswordstrengthLayer not in browser_layers + + def test_plugin_removed(self, portal): + """Test if plugin is removed to acl_users.""" + from pas.plugins.passwordstrength import PLUGIN_ID + + pas = api.portal.get_tool("acl_users") + assert PLUGIN_ID not in pas.objectIds() diff --git a/tox.ini b/tox.ini index 3724172..d3d50ec 100644 --- a/tox.ini +++ b/tox.ini @@ -158,7 +158,7 @@ deps = -c constraints-mxdev.txt commands = - coverage run --source pas.plugins.oidc -m pytest {posargs} --disable-warnings {toxinidir}/tests + coverage run --source pas.plugins.passwordstrength -m pytest {posargs} --disable-warnings {toxinidir}/tests coverage report -m --format markdown coverage xml extras = From 6d43aefc4e7d0dda1d0cd7c7282582a7dfbc93b6 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Mon, 27 Nov 2023 01:02:05 +0100 Subject: [PATCH 09/11] tests --- src/pas/plugins/passwordstrength/__init__.py | 7 ++-- src/pas/plugins/passwordstrength/testing.py | 2 + tests/conftest.py | 22 ----------- tests/docker-compose.yml | 41 -------------------- tests/functional/conftest.py | 14 +------ tests/plugin/test_plugin.py | 6 +-- tests/services/conftest.py | 25 +----------- tests/services/test_services_login_get.py | 10 ++--- tests/setup/test_setup_install.py | 2 +- 9 files changed, 19 insertions(+), 110 deletions(-) delete mode 100644 tests/docker-compose.yml diff --git a/src/pas/plugins/passwordstrength/__init__.py b/src/pas/plugins/passwordstrength/__init__.py index 7b1e7ec..c586c10 100644 --- a/src/pas/plugins/passwordstrength/__init__.py +++ b/src/pas/plugins/passwordstrength/__init__.py @@ -3,7 +3,8 @@ import logging - -_ = MessageFactory("pas.plugins.passwordstrength") -logger = logging.getLogger("pas.plugins.passwordstrength") PLUGIN_ID = "passwordstrength_policy" +PACKAGE_NAME = "pas.plugins.passwordstrength" + +_ = MessageFactory(PACKAGE_NAME) +logger = logging.getLogger(PACKAGE_NAME) diff --git a/src/pas/plugins/passwordstrength/testing.py b/src/pas/plugins/passwordstrength/testing.py index c09b3b5..0e5800e 100644 --- a/src/pas/plugins/passwordstrength/testing.py +++ b/src/pas/plugins/passwordstrength/testing.py @@ -6,6 +6,7 @@ from plone.testing.zope import WSGI_SERVER_FIXTURE import pas.plugins.passwordstrength +import plone.restapi class TestLayer(PloneSandboxLayer): @@ -15,6 +16,7 @@ def setUpZope(self, app, configurationContext): # Load any other ZCML that is required for your tests. # The z3c.autoinclude feature is disabled in the Plone fixture base # layer. + self.loadZCML(package=plone.restapi) self.loadZCML(package=pas.plugins.passwordstrength) def setUpPloneSite(self, portal): diff --git a/tests/conftest.py b/tests/conftest.py index 425984f..fd84c31 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -38,28 +38,6 @@ def is_responsive(url: str) -> bool: return False -@pytest.fixture(scope="session") -def keycloak_service(docker_ip, docker_services): - """Ensure that keycloak service is up and responsive.""" - # `port_for` takes a container port and returns the corresponding host port - port = docker_services.port_for("keycloak", 8080) - url = f"http://{docker_ip}:{port}" - docker_services.wait_until_responsive( - timeout=50.0, pause=0.1, check=lambda: is_responsive(url) - ) - return url - - -@pytest.fixture(scope="session") -def keycloak(keycloak_service): - return { - "issuer": f"{keycloak_service}/realms/plone-test", - "client_id": "plone", - "client_secret": "12345678", # nosec B105 - "scope": ("openid", "profile", "email"), - } - - @pytest.fixture def wait_for(): def func(thread): diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml deleted file mode 100644 index bb2a4e8..0000000 --- a/tests/docker-compose.yml +++ /dev/null @@ -1,41 +0,0 @@ -version: "3.9" - -services: - keycloak: - build: - context: keycloak - args: - KEYCLOAK_VERSION: 22.0.0 - command: ['start-dev', '--import-realm'] - depends_on: - - db - environment: - JAVA_OPTS_APPEND: -Dkeycloak.profile.feature.upload_scripts=enabled - KC_DB: postgres - KC_DB_PASSWORD: postgres - KC_DB_URL: jdbc:postgresql://db/keycloak - KC_DB_USERNAME: postgres - KC_HEALTH_ENABLED: false - KC_HTTP_ENABLED: true - KC_METRICS_ENABLED: false - KC_HOSTNAME_URL: http://127.0.0.1:8180/ - KC_PROXY: reencrypt - KEYCLOAK_ADMIN: admin - KEYCLOAK_ADMIN_PASSWORD: admin - volumes: - - ./keycloak/import:/opt/keycloak/data/import - ports: - - 8180:8080 - - db: - image: postgres:14.9 - healthcheck: - test: [ "CMD", "pg_isready", "-q", "-d", "postgres", "-U", "root" ] - timeout: 45s - interval: 5s - retries: 10 - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: keycloak - POSTGRES_HOST: postgres diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 7747360..3aec130 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -16,20 +16,10 @@ def app(functional): @pytest.fixture() -def portal(functional, keycloak): +def portal(functional): portal = functional["portal"] setSite(portal) - plugin = portal.acl_users.passwordstrength - with api.env.adopt_roles(["Manager", "Member"]): - for key, value in keycloak.items(): - setattr(plugin, key, value) - transaction.commit() - yield portal - with api.env.adopt_roles(["Manager", "Member"]): - for key, value in keycloak.items(): - if key != "scope": - value = "" - setattr(plugin, key, value) + # plugin = portal.acl_users.passwordstrength transaction.commit() diff --git a/tests/plugin/test_plugin.py b/tests/plugin/test_plugin.py index e12d5a2..c3ab2cd 100644 --- a/tests/plugin/test_plugin.py +++ b/tests/plugin/test_plugin.py @@ -15,10 +15,10 @@ def _initialize(self, portal, http_request): @pytest.mark.parametrize( "property,expected", [ - ("create_user", True), - ("create_ticket", True), + # ("p1_re", True), + ("p1_err", "Minimum 8 characters"), ], ) def test_plugin_setup(self, property, expected): plugin = self.plugin - assert plugin.getProperty(property) is expected + assert plugin.getProperty(property) == expected diff --git a/tests/services/conftest.py b/tests/services/conftest.py index 49ba105..10f7a27 100644 --- a/tests/services/conftest.py +++ b/tests/services/conftest.py @@ -4,11 +4,9 @@ from plone.app.testing import TEST_USER_NAME from plone.app.testing import TEST_USER_PASSWORD from plone.restapi.testing import RelativeSession -from urllib.parse import urlparse from zope.component.hooks import setSite import pytest -import requests import transaction @@ -18,11 +16,12 @@ def app(restapi): @pytest.fixture() -def portal(restapi, keycloak): +def portal(restapi): portal = restapi["portal"] setSite(portal) # plugin = portal.acl_users.passwordstrength_policy transaction.commit() + yield portal @pytest.fixture() @@ -59,23 +58,3 @@ def api_manager_request(request_api_factory): request.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) yield request request.auth = () - - -@pytest.fixture() -def keycloak_login(): - def func(url: str): - session = requests.Session() - resp = session.get(url) - soup = BeautifulSoup(resp.content) - data = { - "username": TEST_USER_NAME, - "password": TEST_USER_PASSWORD, - "credentialId": "", - } - next_url = soup.find("form", attrs={"id": "kc-form-login"})["action"] - resp = session.post(next_url, data=data, allow_redirects=False) - location = resp.headers["Location"] - qs = urlparse(location).query - return qs - - return func diff --git a/tests/services/test_services_login_get.py b/tests/services/test_services_login_get.py index 60f9da4..7a8d858 100644 --- a/tests/services/test_services_login_get.py +++ b/tests/services/test_services_login_get.py @@ -6,11 +6,11 @@ class TestServiceLoginGet: def _initialize(self, api_anon_request): self.api_session = api_anon_request - def test_login_get_available(self): - response = self.api_session.get("@login") - assert response.status_code == 200 - data = response.json() - assert isinstance(data, dict) + # def test_login_get_available(self): + # response = self.api_session.get("@login") + # assert response.status_code == 200 + # data = response.json() + # assert isinstance(data, dict) # @pytest.mark.parametrize( # "idx, key, expected", diff --git a/tests/setup/test_setup_install.py b/tests/setup/test_setup_install.py index 97fa722..0ba9a52 100644 --- a/tests/setup/test_setup_install.py +++ b/tests/setup/test_setup_install.py @@ -14,7 +14,7 @@ def test_addon_installed(self, installer): def test_latest_version(self, profile_last_version): """Test latest version of default profile.""" - assert profile_last_version(f"{PACKAGE_NAME}:default") == "1001" + assert profile_last_version(f"{PACKAGE_NAME}:default") == "1000" def test_browserlayer(self, browser_layers): """Test that IPasPluginsPasswordstrengthLayer is registered.""" From 26e6ce5d70b21255308a4db9ee9f4d6575962f48 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Mon, 27 Nov 2023 01:06:24 +0100 Subject: [PATCH 10/11] isort --- .github/workflows/meta.yml | 6 ++---- src/pas/plugins/passwordstrength/__init__.py | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml index 39a164d..f489cda 100644 --- a/.github/workflows/meta.yml +++ b/.github/workflows/meta.yml @@ -5,11 +5,9 @@ name: Meta on: push: branches: - - master - main pull_request: branches: - - master - main workflow_dispatch: @@ -34,8 +32,8 @@ jobs: uses: plone/meta/.github/workflows/dependencies.yml@main release_ready: uses: plone/meta/.github/workflows/release_ready.yml@main - circular: - uses: plone/meta/.github/workflows/circular.yml@main +# circular: +# uses: plone/meta/.github/workflows/circular.yml@main ## # To modify the list of default jobs being created add in .meta.toml: diff --git a/src/pas/plugins/passwordstrength/__init__.py b/src/pas/plugins/passwordstrength/__init__.py index c586c10..d2a1bbb 100644 --- a/src/pas/plugins/passwordstrength/__init__.py +++ b/src/pas/plugins/passwordstrength/__init__.py @@ -3,6 +3,7 @@ import logging + PLUGIN_ID = "passwordstrength_policy" PACKAGE_NAME = "pas.plugins.passwordstrength" From 0899b649fef059302767cad12e43091726cf5b0e Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Mon, 27 Nov 2023 01:08:38 +0100 Subject: [PATCH 11/11] flake --- tests/functional/conftest.py | 2 +- tests/services/conftest.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 3aec130..33b3bf9 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -1,4 +1,4 @@ -from plone import api +# from plone import api from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD from plone.app.testing import TEST_USER_NAME diff --git a/tests/services/conftest.py b/tests/services/conftest.py index 10f7a27..e4407e6 100644 --- a/tests/services/conftest.py +++ b/tests/services/conftest.py @@ -1,4 +1,3 @@ -from bs4 import BeautifulSoup from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD from plone.app.testing import TEST_USER_NAME