diff --git a/.commitlintrc.yml b/.commitlintrc.yml new file mode 100644 index 0000000..ef03960 --- /dev/null +++ b/.commitlintrc.yml @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors +# SPDX-License-Identifier: CC0-1.0 +rules: + body-leading-blank: [2, always] + footer-leading-blank: [2, always] + scope-case: [2, always, lower-case] + subject-case: [2, always, sentence-case] + subject-empty: [2, never] + subject-full-stop: [2, never, .] + subject-max-length: [2, always, 72] + type-empty: [2, never] + type-enum: + [ + 2, + always, + [build, chore, ci, docs, feat, fix, merge, perf, refactor, revert, test], + ] +extends: + - '@commitlint/config-conventional' diff --git a/.git_archival.txt b/.git_archival.txt index 1c1d2e8..5a4899c 100644 --- a/.git_archival.txt +++ b/.git_archival.txt @@ -1,4 +1,4 @@ -Copyright DB Netz AG and contributors +Copyright DB InfraGO AG and contributors SPDX-License-Identifier: CC0-1.0 node: $Format:%H$ diff --git a/.git_commit_template b/.git_commit_template new file mode 100644 index 0000000..8f5e98b --- /dev/null +++ b/.git_commit_template @@ -0,0 +1,23 @@ + + +# type(scope)[!]: (max 50 chars, do not end with period) +# Conventional Commits: https://www.conventionalcommits.org/en/v1.0.0/#summary +# Seven rules of commits: https://chris.beams.io/posts/git-commit/#seven-rules +# +# commit types: +# - build (anything related to the package build) +# - chore (cosmetic commits without behavioral changes to production code) +# - ci (anything related to the CI setup) +# - docs (anything related to the documentation) +# - feat (new feature) +# - fix (bug fix) +# - merge (merge commit) +# - perf (performance improvements) +# - refactor (improvements without externally visible behavior changes) +# - revert (other commit(s) was/were reverted) +# - test (only changes to the test setup) + +# commit scopes: +# - core code: (...) +# - extensions: (...) +# - (docs) diff --git a/.git_commit_template.license b/.git_commit_template.license new file mode 100644 index 0000000..dd5d085 --- /dev/null +++ b/.git_commit_template.license @@ -0,0 +1,2 @@ +# Copyright DB InfraGO AG and contributors +# SPDX-License-Identifier: Apache-2.0 diff --git a/.gitattributes b/.gitattributes index de62da1..e9dd5d5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: CC0-1.0 * text=auto diff --git a/.github/workflows/build-test-publish.yml b/.github/workflows/build-test-publish.yml new file mode 100644 index 0000000..bb6587b --- /dev/null +++ b/.github/workflows/build-test-publish.yml @@ -0,0 +1,71 @@ +# Copyright DB InfraGO AG and contributors +# SPDX-License-Identifier: CC0-1.0 + +name: Build + +on: + pull_request: + push: + branches: [master] + tags: ["v*"] + workflow_dispatch: + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + cache: pip + cache-dependency-path: pyproject.toml + python-version: "3.11" + - name: Upgrade pip + run: python -m pip install -U pip + - name: Install pre-commit + run: python -m pip install pre-commit types-docutils + - name: Run Pre-Commit + run: pre-commit run --all-files + + build: + name: Build wheel + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install dependencies + run: |- + python -m pip install -U pip + python -m pip install build twine + - name: Build packages + run: |- + python -m build + - name: Verify packages + run: |- + python -m twine check dist/* + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: Artifacts + path: 'dist/*' + pypi: + name: Publish to PyPI + runs-on: ubuntu-latest + needs: [build] + if: startsWith(github.ref, 'refs/tags/v') + environment: + name: pypi + url: https://pypi.org/project/capella-diff-tools + permissions: + id-token: write + steps: + - name: Download built wheel + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/commit-check.yml b/.github/workflows/commit-check.yml new file mode 100644 index 0000000..5ce55e3 --- /dev/null +++ b/.github/workflows/commit-check.yml @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors +# SPDX-License-Identifier: CC0-1.0 + +name: Conventional Commits + +on: + pull_request: + branches: [master] + +jobs: + conventional-commits: + runs-on: ubuntu-latest + concurrency: + group: commit-check-pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install commitlint + run: npm install @commitlint/cli @commitlint/config-conventional + - name: Validate commit messages + id: conventional-commits + env: + SHA_FROM: ${{ github.event.pull_request.base.sha }} + SHA_TO: ${{ github.event.pull_request.head.sha }} + run: | + delim="_EOF_$(uuidgen)" + echo "validation-result<<$delim" >> "$GITHUB_OUTPUT" + r=0 + npx commitlint --from "$SHA_FROM" --to "$SHA_TO" >> "$GITHUB_OUTPUT" 2>&1 || r=$? + echo "$delim" >> "$GITHUB_OUTPUT" + exit $r + - name: Find conventional commit comment on PR + uses: peter-evans/find-comment@v3 + if: always() && steps.conventional-commits.outcome == 'failure' + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: conventional commit + - name: Post comment if validation failed + uses: peter-evans/create-or-update-comment@v4 + if: always() && steps.conventional-commits.outcome == 'failure' + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + The pull request does not conform to the conventional commit specification. Please ensure that your commit messages follow the spec: . + We also strongly recommend that you set up your development environment with pre-commit, as described in our [CONTRIBUTING guidelines](https://github.com/DSD-DBS/capella-diff-tools/blob/master/CONTRIBUTING.md). This will run all the important checks right before you commit your changes, and avoids lengthy CI wait time and round trips. + + This is the commit validation log: + ``` + ${{ steps.conventional-commits.outputs.validation-result }} + ``` + + Here are some examples of valid commit messages: + ``` + build: Bump dependency versions + docs(user): Add model creation workflow + feat: Add a monitoring dashboard + ``` + edit-mode: replace diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4e63d8d..b83beef 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,11 +1,13 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: CC0-1.0 name: Docs on: + pull_request: push: - branches: ["master"] + branches: [master] + workflow_dispatch: jobs: sphinx: @@ -13,10 +15,10 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: python-version: "3.11" - name: Upgrade pip @@ -31,7 +33,15 @@ jobs: - name: Create docs run: | make -C docs html + - name: Upload built docs as artifact + uses: actions/upload-artifact@v4 + with: + name: Documentation + path: docs/build/html + if-no-files-found: error + retention-days: 5 - name: Deploy + if: github.ref == 'refs/heads/master' uses: peaceiris/actions-gh-pages@v3 with: force_orphan: true diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 96b4af5..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright DB Netz AG and contributors -# SPDX-License-Identifier: CC0-1.0 - -name: Lint - -on: - push: - branches: ["*"] - -jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: "3.11" - - name: Upgrade pip - run: |- - python -m pip install -U pip - - name: Install pre-commit - run: |- - python -m pip install pre-commit types-docutils - - name: Run Pre-Commit - run: |- - pre-commit run --all-files - pylint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: "3.11" - - name: Upgrade pip - run: |- - python -m pip install -U pip - - name: Install pylint - run: |- - python -m pip install pylint - - name: Run pylint - run: |- - pylint -dfixme capella_diff_tools || exit $(($? & ~24)) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index cc5cf45..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright DB Netz AG and contributors -# SPDX-License-Identifier: CC0-1.0 - -name: Publish package - -on: - workflow_dispatch: - push: - branches: [master] - tags: ["v*"] - pull_request: - -jobs: - publish: - name: Publish artifacts - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@v4 - with: - cache: pip - cache-dependency-path: pyproject.toml - python-version: "3.11" - - name: Install dependencies - run: python -m pip install -U pip build twine - - name: Build packages - run: python -m build - - name: Verify packages - run: python -m twine check dist/* - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: Artifacts - path: 'dist/*' - - name: Publish to PyPI - if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/master' - run: python -m twine upload -u __token__ -p ${{ secrets.PYPI_TOKEN }} --non-interactive dist/* diff --git a/.gitignore b/.gitignore index 975287e..6dddc2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: CC0-1.0 # Byte-compiled / optimized / DLL files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5fd9e4b..39f8f8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,16 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: CC0-1.0 default_install_hook_types: [commit-msg, pre-commit] default_stages: [commit, merge-commit] +minimum_pre_commit_version: 3.2.0 repos: + - repo: https://github.com/gitleaks/gitleaks.git + rev: v8.19.2 + hooks: + - id: gitleaks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-ast @@ -19,50 +24,32 @@ repos: - id: check-toml - id: check-vcs-permalinks - id: check-xml + - id: check-yaml - id: debug-statements - id: destroyed-symlinks - id: end-of-file-fixer - id: fix-byte-order-marker - id: trailing-whitespace - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.11.0 - hooks: - - id: black - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - - repo: https://github.com/PyCQA/docformatter - rev: v1.7.5 - hooks: - - id: docformatter - additional_dependencies: - - docformatter[tomli] - - repo: https://github.com/PyCQA/pydocstyle - rev: 6.3.0 - hooks: - - id: pydocstyle - exclude: '^tests/' - additional_dependencies: - - pydocstyle[toml] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.7.1 - hooks: - - id: mypy - additional_dependencies: - - capellambse==0.6.6 - - types-pyyaml - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.4 + rev: v1.5.5 hooks: - id: insert-license - name: Insert license headers (shell-style comments) + name: Insert Apache license headers (shell-style comments) files: '(?:^|/)(?:.*\.(?:py|sh|toml|ya?ml)|Dockerfile|Makefile)$' exclude: '(?:^|/)\..+|^docs/Makefile$' args: - --detect-license-in-X-top-lines=15 - --license-filepath - - LICENSES/.license_header.txt + - LICENSES/.license_header_apache.txt + - --comment-style + - '#' + - id: insert-license + name: Insert CC0 license headers (shell-style comments) + files: '(?:^|/)(?:codeql-analysis.yml|dependabot.yml|\.(?:pre-commit-config.yaml|(?:git|helm|docker)ignore))$' + args: + - --detect-license-in-X-top-lines=15 + - --license-filepath + - LICENSES/.license_header_cc0.txt - --comment-style - '#' - id: insert-license @@ -72,34 +59,63 @@ repos: args: - --detect-license-in-X-top-lines=15 - --license-filepath - - LICENSES/.license_header.txt + - LICENSES/.license_header_apache.txt - --comment-style - '' - id: insert-license - name: Insert license headers (C-style comments) - files: '\.(?:css|js|ts)$' + name: Insert Apache license headers (C-style comments) + files: '\.(?:s?css|js|ts)$' exclude: '(?:^|/)\..+' args: - --detect-license-in-X-top-lines=15 - --license-filepath - - LICENSES/.license_header.txt + - LICENSES/.license_header_apache.txt - --comment-style - '/*| *| */' - id: insert-license - name: Insert license headers (reST comments) + name: Insert Apache license headers (reST comments) files: '\.rst$' exclude: '(?:^|/)\..+' args: - --detect-license-in-X-top-lines=15 - --license-filepath - - LICENSES/.license_header.txt + - LICENSES/.license_header_apache.txt - --comment-style - '..| |' + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 + hooks: + - id: isort + - repo: https://github.com/PyCQA/docformatter + rev: v1.7.5 + hooks: + - id: docformatter + additional_dependencies: + - docformatter[tomli] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.7 + hooks: + - id: ruff-format + - id: ruff + args: [--extend-ignore=FIX] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.11.2 + hooks: + - id: mypy + additional_dependencies: + - capellambse==0.6.6 + - click + - jinja2 + - markupsafe + - types-pyyaml - repo: https://github.com/fsfe/reuse-tool - rev: v2.1.0 + rev: v4.0.3 hooks: - id: reuse - - repo: https://github.com/qoomon/git-conventional-commits - rev: v2.6.5 + - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook + rev: v9.18.0 hooks: - - id: conventional-commits + - id: commitlint + stages: [commit-msg] + additional_dependencies: + - '@commitlint/config-conventional' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b210f6f..8fd6435 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ @@ -39,8 +39,8 @@ We additionally recommend that you set up your editor / IDE as follows. - _If you use Visual Studio Code_: Consider using a platform which supports third-party language servers more easily, and continue with the next point. - Otherwise, set up the editor to run `black`, `pylint` and `mypy` when saving. - To enable automatic import sorting with `isort`, add the following to your + Otherwise, set up the editor to run `ruff` and `mypy` when saving. To enable + automatic import sorting with `isort`, add the following to your `settings.json`: ```json @@ -54,14 +54,16 @@ We additionally recommend that you set up your editor / IDE as follows. Note that the Pylance language server is not recommended, as it occasionally causes false-positive errors for perfectly valid code. -- _If you do not use VSC_: Set up your editor to use the [python-lsp-server], - and make sure that the relevant plugins are installed. You can install - everything that's needed into the virtualenv with pip: +- _If you do not use VSC_: Set up your editor to use the [python-lsp-server] + and [ruff], and make sure that the relevant pylsp plugins are installed. [python-lsp-server]: https://github.com/python-lsp/python-lsp-server + [ruff]: https://github.com/astral-sh/ruff + + You can install everything that's needed into the virtualenv with pip: ```sh - pip install "python-lsp-server[pylint]" python-lsp-black pyls-isort pylsp-mypy + pip install "python-lsp-server" pyls-isort pylsp-mypy ruff ``` This will provide as-you-type linting as well as automatic formatting on @@ -80,7 +82,7 @@ The key differences are: https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard When writing docstrings for functions, use the imperative style, as per - [PEP-257]). For example, write "Do X and Y" instead of "Does X and Y". + [PEP-257]. For example, write "Do X and Y" instead of "Does X and Y". [pep-257]: https://peps.python.org/pep-0257/ @@ -90,20 +92,18 @@ The key differences are: automated tools pick up the full base class docstring instead, and is therefore more useful in IDEs etc. -- **Linting**: Use [pylint] for static code analysis, and [mypy] for static +- **Linting**: Use [ruff] for static code analysis, and [mypy] for static type checking. - [pylint]: https://github.com/PyCQA/pylint [mypy]: https://github.com/python/mypy -- **Formatting**: Use [black] as code auto-formatter. The maximum line length +- **Formatting**: Use [ruff] as code auto-formatter. The maximum line length is 79, as per [PEP-8]. This setting should be automatically picked up from the `pyproject.toml` file. The reason for the shorter line length is that it avoids wrapping and overflows in side-by-side split views (e.g. diffs) if there's also information displayed to the side of it (e.g. a tree view of the modified files). - [black]: https://github.com/psf/black [pep-8]: https://www.python.org/dev/peps/pep-0008/ Be aware of the different line length of 72 for docstrings. We currently do @@ -136,12 +136,7 @@ The key differences are: [pep-604-style unions]: https://www.python.org/dev/peps/pep-0604/ -- **Python style rules**: For conflicting parts, the [Black code style] wins. - If you have set up black correctly, you don't need to worry about this though - :) - - [black code style]: - https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html +- **Python style rules**: The auto-formatter wins. - When working with `dict`s, consider using `t.TypedDict` instead of a more generic `dict[str, float|int|str]`-like annotation where possible, as the diff --git a/LICENSES/.license_header.txt b/LICENSES/.license_header.txt deleted file mode 100644 index c3fb022..0000000 --- a/LICENSES/.license_header.txt +++ /dev/null @@ -1,2 +0,0 @@ -Copyright DB Netz AG and contributors -SPDX-License-Identifier: Apache-2.0 diff --git a/LICENSES/.license_header_apache.txt b/LICENSES/.license_header_apache.txt new file mode 100644 index 0000000..02c8c23 --- /dev/null +++ b/LICENSES/.license_header_apache.txt @@ -0,0 +1,2 @@ +Copyright DB InfraGO AG and contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/LICENSES/.license_header_cc0.txt b/LICENSES/.license_header_cc0.txt new file mode 100644 index 0000000..b689e74 --- /dev/null +++ b/LICENSES/.license_header_cc0.txt @@ -0,0 +1,2 @@ +Copyright DB InfraGO AG and contributors +SPDX-License-Identifier: CC0-1.0 diff --git a/README.md b/README.md index 3619651..6b4bbd6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ @@ -119,7 +119,7 @@ look at our [guidelines for contributors](CONTRIBUTING.md) for details. This project is compliant with the [REUSE Specification Version 3.0](https://git.fsfe.org/reuse/docs/src/commit/d173a27231a36e1a2a3af07421f5e557ae0fec46/spec.md). -Copyright DB Netz AG, licensed under Apache 2.0 (see full text in +Copyright DB InfraGO AG, licensed under Apache 2.0 (see full text in [LICENSES/Apache-2.0.txt](LICENSES/Apache-2.0.txt)) Dot-files are licensed under CC0-1.0 (see full text in diff --git a/capella_diff_tools/__init__.py b/capella_diff_tools/__init__.py index 0401787..2c44552 100644 --- a/capella_diff_tools/__init__.py +++ b/capella_diff_tools/__init__.py @@ -1,6 +1,7 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """The capella_diff_tools package.""" + from importlib import metadata try: diff --git a/capella_diff_tools/__main__.py b/capella_diff_tools/__main__.py index 62db684..d80de55 100644 --- a/capella_diff_tools/__main__.py +++ b/capella_diff_tools/__main__.py @@ -1,6 +1,7 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Main entry point into capella_diff_tools.""" + from __future__ import annotations import datetime @@ -135,7 +136,7 @@ def _get_revision_info( class CustomYAMLDumper(yaml.SafeDumper): """A custom YAML dumper that can serialize markupsafe.Markup.""" - def represent_markup(self, data): + def represent_markup(self, data: t.Any) -> t.Any: """Represent markupsafe.Markup with the '!html' tag.""" return self.represent_scalar("!html", str(data)) diff --git a/capella_diff_tools/compare.py b/capella_diff_tools/compare.py index 64318f0..1cf8c46 100644 --- a/capella_diff_tools/compare.py +++ b/capella_diff_tools/compare.py @@ -1,6 +1,7 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Functions for comparing different types of objects in a Capella model.""" + from __future__ import annotations __all__ = [ @@ -221,7 +222,7 @@ def _obj2diff( for attr in dir(type(old)): if not isinstance( getattr(type(old), attr, None), - (m.BasePOD, m.AttrProxyAccessor, m.LinkAccessor), + m.BasePOD | m.AttrProxyAccessor | m.LinkAccessor, ): continue @@ -290,9 +291,9 @@ def _obj2diff( def _serialize_obj(obj: t.Any) -> t.Any: if isinstance(obj, m.ModelElement): return {"uuid": obj.uuid, "display_name": _get_name(obj)} - elif isinstance(obj, m.ElementList): + if isinstance(obj, m.ElementList): return [{"uuid": i.uuid, "display_name": _get_name(i)} for i in obj] - elif isinstance(obj, (enum.Enum, enum.Flag)): + if isinstance(obj, enum.Enum | enum.Flag): return obj.name return obj diff --git a/capella_diff_tools/report.html.jinja b/capella_diff_tools/report.html.jinja index d033e67..e621356 100644 --- a/capella_diff_tools/report.html.jinja +++ b/capella_diff_tools/report.html.jinja @@ -1,5 +1,5 @@ {#- - Copyright DB Netz AG and contributors + Copyright DB InfraGO AG and contributors SPDX-License-Identifier: Apache-2.0 -#} diff --git a/capella_diff_tools/report.py b/capella_diff_tools/report.py index e3af53a..137a008 100644 --- a/capella_diff_tools/report.py +++ b/capella_diff_tools/report.py @@ -1,4 +1,4 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 from __future__ import annotations @@ -25,7 +25,7 @@ class _CustomLoader(yaml.SafeLoader): - def construct_html(self, node): + def construct_html(self, node: t.Any) -> t.Any: data = self.construct_scalar(node) return markupsafe.Markup(data) @@ -33,21 +33,21 @@ def construct_html(self, node): _CustomLoader.add_constructor("!html", _CustomLoader.construct_html) -def _diff_text(previous, current): +def _diff_text(previous: str, current: str) -> t.Any: dmp = diff_match_patch.diff_match_patch() diff = dmp.diff_main("\n".join(previous), "\n".join(current)) dmp.diff_cleanupSemantic(diff) return dmp.diff_prettyHtml(diff) -def _diff_objects(previous, current): +def _diff_objects(previous: t.Any, current: t.Any) -> t.Any: return ( f"{previous['display_name']}" f" → {current['display_name']}" ) -def _diff_lists(previous, current): +def _diff_lists(previous: t.Any, current: t.Any) -> t.Any: out = [] previous = {item["uuid"]: item for item in previous} for item in current: @@ -67,7 +67,7 @@ def _diff_lists(previous, current): return "" -def _traverse_and_diff(data): +def _traverse_and_diff(data: t.Any) -> t.Any: """Traverse the data and perform diff on text fields. This function recursively traverses the data and performs an HTML @@ -84,16 +84,16 @@ def _traverse_and_diff(data): ): prev_type = type(value["previous"]) curr_type = type(value["current"]) - if prev_type == curr_type == str: + if prev_type is curr_type is str: diff = _diff_text( value["previous"].splitlines(), value["current"].splitlines(), ) updates[key] = {"diff": diff} - elif prev_type == curr_type == dict: + elif prev_type is curr_type is dict: diff = _diff_objects(value["previous"], value["current"]) updates[key] = {"diff": diff} - elif prev_type == curr_type == list: + elif prev_type is curr_type is list: diff = _diff_lists(value["previous"], value["current"]) updates[key] = {"diff": diff} @@ -107,7 +107,7 @@ def _traverse_and_diff(data): return data -def _compute_diff_stats(data): +def _compute_diff_stats(data: t.Any) -> t.Any: """Compute the diff stats for the data. This function collects the diff stats for the data, i.e. how many diff --git a/capella_diff_tools/types.py b/capella_diff_tools/types.py index 4a1710d..c3a51f3 100644 --- a/capella_diff_tools/types.py +++ b/capella_diff_tools/types.py @@ -1,6 +1,7 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Types for annotating functions in the diff tool.""" + from __future__ import annotations import datetime diff --git a/docs/Makefile b/docs/Makefile index fdfe666..165c707 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,4 +1,4 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: CC0-1.0 # Minimal makefile for Sphinx documentation diff --git a/docs/make.bat b/docs/make.bat index ab614db..9f24710 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,5 +1,5 @@ @ECHO OFF -REM Copyright DB Netz AG and contributors +REM Copyright DB InfraGO AG and contributors REM SPDX-License-Identifier: CC0-1.0 pushd %~dp0 diff --git a/docs/source/_static/.gitkeep b/docs/source/_static/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/source/_static/github-logo.svg b/docs/source/_static/github-logo.svg deleted file mode 100644 index a407b96..0000000 --- a/docs/source/_static/github-logo.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/docs/source/_static/screenshot.png.license b/docs/source/_static/screenshot.png.license index c3fb022..02c8c23 100644 --- a/docs/source/_static/screenshot.png.license +++ b/docs/source/_static/screenshot.png.license @@ -1,2 +1,2 @@ -Copyright DB Netz AG and contributors +Copyright DB InfraGO AG and contributors SPDX-License-Identifier: Apache-2.0 diff --git a/docs/source/conf.py b/docs/source/conf.py index 3841a87..16a036d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,4 +1,4 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Configuration file for Sphinx.""" @@ -45,7 +45,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -# exclude_patterns = [] +exclude_patterns: list[str] = [] # -- General information about the project ----------------------------------- @@ -93,7 +93,7 @@ { "name": "GitHub", "url": "https://github.com/DSD-DBS/capella-diff-tools", - "html": '', + "html": '', "class": "", }, ], diff --git a/docs/source/index.rst b/docs/source/index.rst index 819e174..3b3b6ab 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,5 +1,5 @@ .. - Copyright DB Netz AG and contributors + Copyright DB InfraGO AG and contributors SPDX-License-Identifier: Apache-2.0 Welcome to Capella Diff Tools's documentation! diff --git a/git-conventional-commits.json b/git-conventional-commits.json deleted file mode 100644 index 525cbf0..0000000 --- a/git-conventional-commits.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "convention" : { - "commitTypes": [ - "build", - "chore", - "ci", - "docs", - "feat", - "fix", - "merge", - "perf", - "refactor", - "revert", - "test" - ], - "commitScopes": [] - } -} diff --git a/git-conventional-commits.json.license b/git-conventional-commits.json.license deleted file mode 100644 index 95e8b6e..0000000 --- a/git-conventional-commits.json.license +++ /dev/null @@ -1,2 +0,0 @@ -Copyright DB Netz AG and contributors -SPDX-License-Identifier: CC0-1.0 diff --git a/pyproject.toml b/pyproject.toml index e71b346..635407a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,4 @@ -# Copyright DB Netz AG and contributors +# Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 [build-system] @@ -11,10 +11,10 @@ dynamic = ["version"] name = "capella-diff-tools" description = "Tools for comparing different versions of a Capella model" readme = "README.md" -requires-python = ">=3.11, <3.13" +requires-python = ">=3.11, <3.14" license = { text = "Apache-2.0" } authors = [ - { name = "DB Netz AG" }, + { name = "DB InfraGO AG" }, ] keywords = [] classifiers = [ @@ -25,6 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dependencies = [ "capellambse>=0.6.6,<0.7", @@ -54,10 +55,6 @@ test = [ [project.scripts] capella-diff-tool = "capella_diff_tools.__main__:main" -[tool.black] -line-length = 79 -target-version = ["py311"] - [tool.coverage.run] branch = true command_line = "-m pytest" @@ -82,6 +79,8 @@ line_length = 79 [tool.mypy] check_untyped_defs = true +disallow_incomplete_defs = true +disallow_untyped_defs = true no_implicit_optional = true show_error_codes = true warn_redundant_casts = true @@ -90,102 +89,16 @@ python_version = "3.11" [[tool.mypy.overrides]] module = ["tests.*"] -allow_incomplete_defs = true -allow_untyped_defs = true +disallow_incomplete_defs = false +disallow_untyped_defs = false [[tool.mypy.overrides]] # Untyped third party libraries module = [ - # ... + "diff_match_patch.*", ] ignore_missing_imports = true -[tool.pydocstyle] -convention = "numpy" -add-select = [ - "D212", # Multi-line docstring summary should start at the first line - "D402", # First line should not be the function’s “signature” - "D417", # Missing argument descriptions in the docstring -] -add-ignore = [ - "D1", # Missing docstring in public module/class/function/... - "D201", # No blank lines allowed before function docstring # auto-formatting - "D202", # No blank lines allowed after function docstring # auto-formatting - "D203", # 1 blank line required before class docstring # auto-formatting - "D204", # 1 blank line required after class docstring # auto-formatting - "D211", # No blank lines allowed before class docstring # auto-formatting - "D213", # Multi-line docstring summary should start at the second line -] - -[tool.pylint.format] -ignore-long-lines = '^\s*(?:(?:__ |\.\. __: )?https?://[^ ]+$|def test_.*|[A-Za-z0-9_\.]+(?: ?:)?$)' - -[tool.pylint.master] -max-line-length = 79 - -[tool.pylint.messages_control] -disable = [ - "broad-except", - "global-statement", - "import-outside-toplevel", - "invalid-name", - "missing-class-docstring", - "missing-function-docstring", - "missing-module-docstring", - "no-else-break", - "no-else-continue", - "no-else-raise", - "no-else-return", - "protected-access", - "redefined-builtin", - "too-few-public-methods", - "too-many-ancestors", - "too-many-arguments", - "too-many-boolean-expressions", - "too-many-branches", - "too-many-instance-attributes", - "too-many-lines", - "too-many-locals", - "too-many-public-methods", - "too-many-return-statements", - "too-many-statements", - - # Auto-formatting - "bad-indentation", - "inconsistent-quotes", - "missing-final-newline", - "mixed-line-endings", - "multiple-imports", - "multiple-statements", - "trailing-newlines", - "trailing-whitespace", - "unexpected-line-ending-format", - "ungrouped-imports", - "wrong-import-order", - "wrong-import-position", - - # Handled by mypy - "arguments-differ", - "assignment-from-no-return", - "import-error", - "missing-kwoa", - "no-member", - "no-value-for-parameter", - "redundant-keyword-arg", - "signature-differs", - "syntax-error", - "too-many-function-args", - "unbalanced-tuple-unpacking", - "undefined-variable", - "unexpected-keyword-arg", -] -enable = [ - "c-extension-no-member", - "deprecated-pragma", - "use-symbolic-message-instead", - "useless-suppression", -] - [tool.pytest.ini_options] addopts = """ --import-mode=importlib @@ -195,6 +108,82 @@ addopts = """ testpaths = ["tests"] xfail_strict = true +[tool.ruff] +line-length = 79 + +[tool.ruff.lint] +extend-select = [ + "ARG", # flake8-unused-arguments + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "C90", # mccabe + "D", # pydocstyle + "D212", # "Multi-line docstring summary should start at the first line" + "D402", # "First line should not be the function’s 'signature'" + "D417", # "Missing argument descriptions in the docstring" + "DTZ", # flake8-datetimez + "ERA", # eradicate + "FA", # flake8-future-annotations + "FBT", # flake8-boolean-trap + "FIX", # flake8-fixme + "FURB", # refurb + "G", # flake8-logging-format + "ICN", # flake8-import-conventions + "ISC001", # "Implicitly concatenated string literals on one line" + "ISC003", # "Explicitly concatenated string should be implicitly concatenated" + "LOG", # flake8-logging + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "RET", # flake8-return + "RUF", # ruff + "SIM", # flake8-simplify + "TCH005", # "Found empty type-checking block" + "T1", # flake8-debugger + "UP", # pyupgrade + "YTT", # flake8-2020 +] +extend-ignore = [ + "D1", # Missing docstring in _ + "D201", # No blank lines allowed before function docstring # auto-formatting + "D202", # No blank lines allowed after function docstring # auto-formatting + "D203", # 1 blank line required before class docstring # auto-formatting + "D204", # 1 blank line required after class docstring # auto-formatting + "D211", # No blank lines allowed before class docstring # auto-formatting + "D213", # Multi-line docstring summary should start at the second line + "DTZ001", # `tzinfo=None` passed to `datetime.datetime()` + "DTZ005", # `tz=None` passed to `datetime.datetime.now()` + "E402", # Module level import not at top of file + "F403", # `from _ import *` used; unable to detect undefined names + "F405", # `_` may be undefined, or defined from star imports + "PLC0414", # Import alias does not rename original package # used for explicit reexports + "PLR0904", # Too many public methods + "PLR0911", # Too many return statements + "PLR0912", # Too many branches + "PLR0913", # Too many arguments in function definition + "PLR0914", # Too many local variables + "PLR0915", # Too many statements + "PLR0916", # Too many Boolean expressions + "PLR0917", # Too many positional arguments + "SIM108", # Use ternary operator instead of `if`-`else`-block +] + +[tool.ruff.lint.extend-per-file-ignores] +"__init__.py" = [ + "PLE0604", # Invalid object in `__all__`, must contain only strings # false-positive when unpacking imported submodule __all__ +] +"tests/test_*.py" = [ + "F811", # Redefinition of unused `_` from line _ + "PLR2004", # Magic value used in comparison, consider replacing `_` with a constant variable +] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" +ignore-decorators = ["typing.overload"] + +[tool.ruff.lint.mccabe] +max-complexity = 14 + [tool.setuptools] platforms = ["any"] zip-safe = false