diff --git a/.github/workflows/.beman_submodule b/.github/workflows/.beman_submodule index d48589c..d2a6912 100644 --- a/.github/workflows/.beman_submodule +++ b/.github/workflows/.beman_submodule @@ -1,4 +1,4 @@ [beman_submodule] remote=https://github.com/bemanproject/infra-workflows.git -commit_hash=132186fc8bca457512d7fa0400be34ea958542a0 +commit_hash=962bc39d246b4dd3e1fc34250a66d188610c30e7 allow_untracked_files=True diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index c6b707b..d4a39b1 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -26,7 +26,6 @@ jobs: {"preset": "llvm-release", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"}, {"preset": "appleclang-debug", "runner": "macos-latest"}, {"preset": "appleclang-release", "runner": "macos-latest"}, - {"preset": "msvc-debug", "runner": "windows-latest"}, {"preset": "msvc-release", "runner": "windows-latest"} ] @@ -113,7 +112,7 @@ jobs: { "cxxversions": ["c++23"], "tests": [ { "stdlibs": ["stl"], - "tests": ["Debug.Default", "Release.Default", "Release.MaxSan"] + "tests": ["Debug.Default", "Release.Default"] } ] }, diff --git a/.github/workflows/reusable-beman-build-and-test.yml b/.github/workflows/reusable-beman-build-and-test.yml index a347c4c..b1cd4f1 100644 --- a/.github/workflows/reusable-beman-build-and-test.yml +++ b/.github/workflows/reusable-beman-build-and-test.yml @@ -161,6 +161,7 @@ jobs: exclude = $GITHUB_WORKSPACE/tests/.* coveralls = $GITHUB_WORKSPACE/coverage.json coveralls-pretty = yes + merge-mode-functions = separate EOF git config --global --add safe.directory $GITHUB_WORKSPACE gcovr --verbose --config gcovr.cfg . diff --git a/.github/workflows/reusable-beman-pre-commit.yml b/.github/workflows/reusable-beman-pre-commit.yml index 1f3dc0f..1ca9ea3 100644 --- a/.github/workflows/reusable-beman-pre-commit.yml +++ b/.github/workflows/reusable-beman-pre-commit.yml @@ -18,10 +18,6 @@ jobs: with: python-version: 3.13 - # We wish to run pre-commit on all files instead of the changes - # only made in the push commit. - # - # So linting error persists when there's formatting problem. - uses: pre-commit/action@v3.0.1 pre-commit-pr: @@ -51,17 +47,7 @@ jobs: with: python-version: 3.13 - # we only lint on the changed file in PR. - - name: Get Changed Files - id: changed-files - uses: tj-actions/changed-files@v45 - - # See: - # https://github.com/tj-actions/changed-files?tab=readme-ov-file#using-local-git-directory- - uses: pre-commit/action@v3.0.1 - id: run-pre-commit - with: - extra_args: --files ${{ steps.changed-files.outputs.all_changed_files }} # Review dog posts the suggested change from pre-commit to the pr. - name: suggester / pre-commit diff --git a/.github/workflows/reusable-beman-submodule-check.yml b/.github/workflows/reusable-beman-submodule-check.yml index 10029d3..726bfde 100644 --- a/.github/workflows/reusable-beman-submodule-check.yml +++ b/.github/workflows/reusable-beman-submodule-check.yml @@ -17,4 +17,4 @@ jobs: uses: actions/checkout@v4 - name: beman submodule consistency check run: | - (set -o pipefail; ${{ inputs.infra_path }}/tools/beman-submodule/beman-submodule status | grep -qvF '+') + (set -eo pipefail; while read line ; do echo $line | grep -qvF '+' ; done < <(${{ inputs.infra_path }}/tools/beman-submodule/beman-submodule status)) diff --git a/.github/workflows/reusable-beman-update-pre-commit.yml b/.github/workflows/reusable-beman-update-pre-commit.yml new file mode 100644 index 0000000..1b694a6 --- /dev/null +++ b/.github/workflows/reusable-beman-update-pre-commit.yml @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: Pre-commit auto-update + +on: + workflow_call: + +jobs: + auto-update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.13 + - name: Install pre-commit + run: pip install pre-commit + - name: Run pre-commit autoupdate + run: pre-commit autoupdate + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: update/pre-commit-autoupdate + title: Auto-update pre-commit hooks + commit-message: Auto-update pre-commit hooks + body: Update versions of tools in pre-commit configs to latest version + labels: dependencies diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index baacd4b..e39ac28 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,3 +24,4 @@ repos: hooks: - id: gersemi name: CMake linting + exclude: ^.*/tests/.*/data/ # Exclude test data directories diff --git a/CMakePresets.json b/CMakePresets.json index bd35911..4e7737a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -93,17 +93,6 @@ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake" } }, - { - "name": "msvc-debug", - "displayName": "MSVC Debug Build", - "inherits": [ - "_root-config", - "_debug-base" - ], - "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake" - } - }, { "name": "msvc-release", "displayName": "MSVC Release Build", @@ -164,13 +153,6 @@ "_root-build" ] }, - { - "name": "msvc-debug", - "configurePreset": "msvc-debug", - "inherits": [ - "_root-build" - ] - }, { "name": "msvc-release", "configurePreset": "msvc-release", @@ -221,11 +203,6 @@ "inherits": "_test_base", "configurePreset": "appleclang-release" }, - { - "name": "msvc-debug", - "inherits": "_test_base", - "configurePreset": "msvc-debug" - }, { "name": "msvc-release", "inherits": "_test_base", @@ -335,23 +312,6 @@ } ] }, - { - "name": "msvc-debug", - "steps": [ - { - "type": "configure", - "name": "msvc-debug" - }, - { - "type": "build", - "name": "msvc-debug" - }, - { - "type": "test", - "name": "msvc-debug" - } - ] - }, { "name": "msvc-release", "steps": [ diff --git a/infra/.beman_submodule b/infra/.beman_submodule index 9c8e962..fa0afe9 100644 --- a/infra/.beman_submodule +++ b/infra/.beman_submodule @@ -1,3 +1,3 @@ [beman_submodule] remote=https://github.com/bemanproject/infra.git -commit_hash=78de7eb4ff54bd12c9abb790107edc86bcda07d8 +commit_hash=d7c51d169860c5ceeb8a026859bd24820ab6826d diff --git a/infra/.github/CODEOWNERS b/infra/.github/CODEOWNERS index 856bd53..4ff90a4 100644 --- a/infra/.github/CODEOWNERS +++ b/infra/.github/CODEOWNERS @@ -1 +1 @@ -* @ednolan @neatudarius @rishyak @wusatosi +* @ednolan @neatudarius @rishyak @wusatosi @JeffGarland diff --git a/infra/.github/workflows/beman-tidy.yml b/infra/.github/workflows/beman-tidy.yml index d5611f8..46221e6 100644 --- a/infra/.github/workflows/beman-tidy.yml +++ b/infra/.github/workflows/beman-tidy.yml @@ -7,10 +7,13 @@ on: branches: - main pull_request: + workflow_call: workflow_dispatch: + schedule: + - cron: '0 6 * * *' # 09:00AM EEST (@neatudarius' timezone) jobs: - tests: + run_linter: runs-on: ubuntu-latest defaults: run: @@ -28,9 +31,81 @@ jobs: - name: Run linter run: | - echo "Running linter" uv run ruff check --diff + run_tests: + runs-on: ubuntu-latest + defaults: + run: + working-directory: tools/beman-tidy + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Sync environment + run: | + uv sync + - name: Run tests run: | uv run pytest tests/ -v + + build_and_install: + runs-on: ubuntu-latest + defaults: + run: + working-directory: tools/beman-tidy + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Sync environment + run: | + uv sync + + - name: Build and install beman-tidy + run: | + uv clean + uv build + python3 -m pip install dist/beman_tidy-0.1.0-py3-none-any.whl --force-reinstall + beman-tidy --help + + run_on_exemplar: + runs-on: ubuntu-latest + defaults: + run: + working-directory: tools/beman-tidy + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Sync environment + run: | + uv sync + + - name: Build and install beman-tidy + run: | + uv clean + uv build + python3 -m pip install dist/beman_tidy-0.1.0-py3-none-any.whl --force-reinstall + beman-tidy --help + + - name: Run installed beman-tidy on exemplar repo + run: | + git clone https://github.com/bemanproject/exemplar.git + cd exemplar/ # Testing that beman-tidy can be run from any path, e.g. from the exemplar repo. + beman-tidy --verbose --require-all . + + create-issue-when-fault: + needs: [run_linter, run_tests, build_and_install, run_on_exemplar] + if: failure() && (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') + uses: ./.github/workflows/reusable-beman-create-issue-when-fault.yml diff --git a/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml b/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml new file mode 100644 index 0000000..024a51f --- /dev/null +++ b/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: 'Beman issue creation workflow' +on: + workflow_call: + workflow_dispatch: +jobs: + create-issue: + runs-on: ubuntu-latest + steps: + # See https://github.com/cli/cli/issues/5075 + - uses: actions/checkout@v4 + - name: Create issue + run: | + issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] infra repo CI job failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end') + body="**CI job failure Report** + - **Time of Failure**: $(date -u '+%B %d, %Y, %H:%M %Z') + - **Commit**: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) + - **Action Run**: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + The scheduled job triggered by cron has failed. + Please investigate the logs and recent changes associated with this commit or rerun the workflow if you believe this is an error." + if [[ $issue_num -eq -1 ]]; then + gh issue create --repo ${{ github.repository }} --title "[SCHEDULED-BUILD] infra repo CI job failure" --body "$body" --assignee ${{ github.actor }} + else + gh issue comment --repo ${{ github.repository }} $issue_num --body "$body" + fi + env: + GH_TOKEN: ${{ github.token }} diff --git a/infra/.pre-commit-config.yaml b/infra/.pre-commit-config.yaml index 3c22d57..8641cfa 100644 --- a/infra/.pre-commit-config.yaml +++ b/infra/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: hooks: - id: gersemi name: CMake linting + exclude: ^.*/tests/.*/data/ # Exclude test data directories # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) diff --git a/infra/LICENSE b/infra/LICENSE index 111a208..f6db814 100644 --- a/infra/LICENSE +++ b/infra/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -216,15 +217,3 @@ conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. - -============================================================================== -Software from third parties included in the Beman Project: -============================================================================== -The Beman Project contains third party software which is under different license -terms. All such code will be identified clearly using at least one of two -mechanisms: -1) It will be in a separate directory tree with its own `LICENSE.txt` or - `LICENSE` file at the top containing the specific license and restrictions - which apply to that software, or -2) It will contain specific license and restriction terms at the top of every - file. diff --git a/infra/README.md b/infra/README.md index 512b4b7..f40ebc1 100644 --- a/infra/README.md +++ b/infra/README.md @@ -2,8 +2,10 @@ -This repository contains the infrastructure for The Beman Project. This is NOT a library repository, so it does not -respect the usual structure of a Beman library repository nor The Beman Standard! +[![beman-tidy tests](https://github.com/bemanproject/infra/actions/workflows/beman-tidy.yml/badge.svg)](https://github.com/bemanproject/infra/actions/workflows/beman-tidy.yml) + +This repository contains the infrastructure for The Beman Project. This is NOT a library repository, +so it does not respect the usual structure of a Beman library repository nor The Beman Standard! ## Description diff --git a/infra/cmake/msvc-toolchain.cmake b/infra/cmake/msvc-toolchain.cmake index 9b8f1b8..c2fffa7 100644 --- a/infra/cmake/msvc-toolchain.cmake +++ b/infra/cmake/msvc-toolchain.cmake @@ -23,8 +23,7 @@ set(CMAKE_CXX_COMPILER cl) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") # /Zi flag (add debug symbol) is needed when using address sanitizer # See C5072: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-c5072 - set(SANITIZER_FLAGS "/Zi") - # set(SANITIZER_FLAGS "/fsanitize=address /Zi") + set(SANITIZER_FLAGS "/fsanitize=address /Zi") endif() set(CMAKE_CXX_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") diff --git a/infra/tools/beman-tidy/README.md b/infra/tools/beman-tidy/README.md index c01045e..be092e4 100644 --- a/infra/tools/beman-tidy/README.md +++ b/infra/tools/beman-tidy/README.md @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ## Description `beman-tidy` is a tool used to check and apply -[The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). +[The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). Purpose: The tool is used to `check` (`--dry-run`) and `apply` (`--fix-inplace`) the Beman Standard to a repository. Note: `2025-06-07`: In order to make the best and quickly use of the tool in the entire organization, most of the @@ -67,7 +67,7 @@ options: --verbose, --no-verbose print verbose output for each check --require-all, --no-require-all - all checks are required regardless of the check type (e.g., RECOMMENDATION becomes REQUIREMENT) + all checks are required regardless of the check type (e.g., Recommendation becomes Requirement) --checks CHECKS array of checks to run ``` @@ -76,77 +76,98 @@ options: ```shell # dry-run, require-all, non-verbose $ uv run beman-tidy /path/to/exemplar --require-all -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). +Summary Requirement: 18 checks passed, 1 checks failed, 5 checks skipped, 23 checks not implemented. +Summary Recommendation: 0 checks passed, 0 checks failed, 0 checks skipped, 0 checks not implemented. -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Coverage RECOMMENDATION: 66.67% (2/3 checks passed). +Coverage Requirement: 95.83% (23/24 checks passed). +Coverage Recommendation: 0.00% (0/0 checks passed). +Coverage TOTAL: 95.83% (23/24 checks passed). # dry-run, non-require-all, non-verbose -$ uv run beman-tidy /path/to/exemplar -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). - -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Note: RECOMMENDATIONs are not included (--require-all NOT set). +Summary Requirement: 13 checks passed, 1 checks failed, 3 checks skipped, 9 checks not implemented. +Summary Recommendation: 5 checks passed, 0 checks failed, 2 checks skipped, 14 checks not implemented. +Coverage Requirement: 66.67% (16/24 checks passed). +Coverage Recommendation: 100.00% (7/7 checks passed). +Coverage TOTAL: 74.19% (23/31 checks passed). ``` -or verbose mode: +or verbose mode without errors: ```shell # dry-run, require-all, verbose mode - no errors -$ uv run beman-tidy /path/to/exemplar --require-all --verbose beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED +Running check [Requirement][license.approved] ... +[info ][license.approved ]: Valid Apache License - Version 2.0 with LLVM Exceptions found in LICENSE file. + check [Requirement][license.approved] ... passed + +Running check [Requirement][license.apache_llvm] ... + check [Requirement][license.apache_llvm] ... passed + +Running check [Requirement][license.criteria] ... +[skipped ][license.criteria ]: beman-tidy cannot actually check license.criteria. Please ignore this message if license.approved has passed. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licensecriteria for more information. +Running check [Requirement][license.criteria] ... skipped -Running check [REQUIREMENT][README.BADGES] ... - check [REQUIREMENT][README.BADGES] ... PASSED +... + +Running check [Requirement][readme.title] ... + check [Requirement][readme.title] ... passed -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED +Running check [Requirement][readme.badges] ... + check [Requirement][readme.badges] ... passed -Running check [RECOMMENDATION][DIRECTORY.SOURCES] ... -[WARNING ][DIRECTORY.SOURCES ]: The directory '/Users/dariusn/dev/dn/git/Beman/exemplar/src/beman/exemplar' does not exist. - check [RECOMMENDATION][DIRECTORY.SOURCES] ... FAILED +Running check [Requirement][readme.implements] ... + check [Requirement][readme.implements] ... passed +... beman-tidy pipeline finished. -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). +Summary Requirement: 19 checks passed, 0 checks failed, 3 checks skipped, 23 checks not implemented. +Summary Recommendation: 0 checks passed, 0 checks failed, 2 checks skipped, 0 checks not implemented. -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Coverage RECOMMENDATION: 66.67% (2/3 checks passed). +Coverage Requirement: 100.00% (24/24 checks passed). +Coverage Recommendation: 0.00% (0/0 checks passed). +Coverage TOTAL: 100.00% (24/24 checks passed). ``` +or verbose mode with errors: + ```shell -# dry-run, require-all, verbose mode - no errors -$ uv run beman-tidy /path/to/exemplar --require-all --verbose +# dry-run, require-all, verbose mode - with errors beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED +Running check [Requirement][license.approved] ... +[info ][license.approved ]: Valid Apache License - Version 2.0 with LLVM Exceptions found in LICENSE file. + check [Requirement][license.approved] ... passed + +Running check [Requirement][license.apache_llvm] ... + check [Requirement][license.apache_llvm] ... passed -Running check [REQUIREMENT][README.BADGES] ... - check [REQUIREMENT][README.BADGES] ... PASSED +Running check [Requirement][license.criteria] ... +[skipped ][license.criteria ]: beman-tidy cannot actually check license.criteria. Please ignore this message if license.approved has passed. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licensecriteria for more information. +Running check [Requirement][license.criteria] ... skipped -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED +... + +Running check [Requirement][readme.implements] ... + check [Requirement][readme.implements] ... passed -Running check [RECOMMENDATION][DIRECTORY.SOURCES] ... - check [RECOMMENDATION][DIRECTORY.SOURCES] ... PASSED +Running check [Requirement][readme.library_status] ... +[error ][readme.library_status ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' does not contain exactly one of the required statuses from ['**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use)', '**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-api-may-undergo-changes)', '**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-stable-api)', '**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#retired-no-longer-maintained-or-actively-developed)'] + check [Requirement][readme.library_status] ... failed +... beman-tidy pipeline finished. -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 3 checks PASSED, 0 checks FAILED, 35 skipped (NOT implemented). +Summary Requirement: 18 checks passed, 1 checks failed, 3 checks skipped, 23 checks not implemented. +Summary Recommendation: 0 checks passed, 0 checks failed, 2 checks skipped, 0 checks not implemented. -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Coverage RECOMMENDATION: 100.0% (3/3 checks passed). +Coverage Requirement: 95.83% (23/24 checks passed). +Coverage Recommendation: 0.00% (0/0 checks passed). +Coverage TOTAL: 95.83% (23/24 checks passed). ``` - Run beman-tidy on the exemplar repository (fix issues in-place): diff --git a/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml b/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml index 4751997..aa45653 100644 --- a/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -1,163 +1,139 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# TODO: 2025-06-07: This file is a partial stable snapshot of the standard. -# TODOs and placeholders will be solved in follow-up PRs when implementing the checks. +# 2025-08-04: Latest Beman Standard (https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md) +# snapshot made by neatudarius. +# Please report any issue related to this file to https://github.com/bemanproject/infra/issues. # LICENSE -LICENSE.APPROVED: - - type: REQUIREMENT - - licenses: - - apache-v2: - - spdx: "Apache License v2.0 with LLVM Exceptions" - - path: "docs/licenses/apache-v2.txt" - - boost-v1: - - spdx: "Boost Software License 1.0" - - path: "docs/licenses/boost-v1.txt" - - mit: - - spdx: "The MIT License" - - path: "docs/licenses/mit.txt" -LICENSE.APACHE_LLVM: - - type: RECOMMENDATION -LICENSE.CRITERIA: - - type: REQUIREMENT +license.approved: + - type: Requirement +license.apache_llvm: + - type: Recommendation +license.criteria: + - type: Requirement # GENERAL -LIBRARY.NAMES: - - type: RECOMMENDATION - - regex: -REPOSITORY.NAME: - - type: RECOMMENDATION - - regex: -REPOSITORY.CODEOWNERS: - - type: REQUIREMENT - - default_group: "@bemanproject/core-reviewers" -REPOSITORY.DISALLOW_GIT_SUBMODULES: - - type: RECOMMENDATION +library.name: + - type: Recommendation + +# REPOSITORY +repository.name: + - type: Requirement +repository.default_branch: + - type: Requirement +repository.codeowners: + - type: Requirement +repository.code_review_rules: + - type: Requirement +repository.disallow_git_submodules: + - type: Recommendation # RELEASE -RELEASE.GITHUB: - - type: REQUIREMENT -RELEASE.NOTES: - - type: RECOMMENDATION -RELEASE.GODBOLT_TRUNK_VERSION: - - type: RECOMMENDATION +release.github: + - type: Requirement +release.notes: + - type: Recommendation +release.godbolt_trunk_version: + - type: Recommendation + # TOP LEVEL -TOPLEVEL.CMAKE: - - type: REQUIREMENT +toplevel.cmake: + - type: Requirement - value: CMakeLists.txt -TOPLEVEL.LICENSE: - - type: REQUIREMENT +toplevel.license: + - type: Requirement - file_name: LICENSE -TOPLEVEL.README: - - type: REQUIREMENT +toplevel.readme: + - type: Requirement - file_name: README.md # README -README.TITLE: - - type: RECOMMENDATION -README.BADGES: - - type: REQUIREMENT - - values: [ +readme.title: + - type: Recommendation +readme.badges: + - type: Requirement + - values: + - library_status: [ "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg)", "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_production_ready_api_may_undergo_changes.svg)", "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_production_ready_stable_api.svg)", "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_retired.svg)" ] -README.PURPOSE: - - type: RECOMMENDATION -README.IMPLEMENTS: - - type: RECOMMENDATION -README.LIBRARY_STATUS: - - type: REQUIREMENT + - standard_target: [ + "![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg)", + "![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp29.svg)" + ] +readme.purpose: + - type: Recommendation +readme.implements: + - type: Recommendation +readme.library_status: + - type: Requirement - values: [ - "**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use)", - "**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-api-may-undergo-changes)", - "**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-stable-api)", - "**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#retired-no-longer-maintained-or-actively-developed)", + "**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use)", + "**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-api-may-undergo-changes)", + "**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-stable-api)", + "**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#retired-no-longer-maintained-or-actively-developed)", ] +readme.license: + - type: Requirement # CMAKE -CMAKE.DEFAULT: - - type: RECOMMENDATION -CMAKE.USE_FETCH_CONTENT: - - type: RECOMMENDATION -CMAKE.PROJECT_NAME: - - type: RECOMMENDATION -CMAKE.PASSIVE_PROJECTS: - - type: RECOMMENDATION -CMAKE.LIBRARY_NAME: - - type: RECOMMENDATION - - regex: -CMAKE.LIBRARY_ALIAS: - - type: REQUIREMENT - - regex: -CMAKE.TARGET_NAMES: - - type: RECOMMENDATION - - regex: -CMAKE.PASSIVE_TARGETS: - - type: REQUIREMENT - - regex: -CMAKE.CONFIG: - - type: REQUIREMENT -CMAKE.SKIP_TESTS: - - type: RECOMMENDATION - - regex: -CMAKE.SKIP_EXAMPLES: - - type: RECOMMENDATION - - regex: -CMAKE.AVOID_PASSTHROUGHS: - - type: RECOMMENDATION +cmake.default: + - type: Recommendation +cmake.use_fetch_content: + - type: Recommendation +cmake.project_name: + - type: Recommendation +cmake.passive_projects: + - type: Recommendation +cmake.library_name: + - type: Recommendation +cmake.library_alias: + - type: Requirement +cmake.target_names: + - type: Recommendation +cmake.passive_targets: + - type: Requirement +cmake.config: + - type: Requirement +cmake.skip_tests: + - type: Recommendation +cmake.skip_examples: + - type: Recommendation +cmake.avoid_passthroughs: + - type: Recommendation # DIRECTORY -DIRECTORY.INTERFACE_HEADERS: - - type: REQUIREMENT - - directory_name: include - - regex: -DIRECTORY.IMPLEMENTATION_HEADERS: - - type: REQUIREMENT - - regex: -DIRECTORY.SOURCES: - - type: REQUIREMENT - - directory_name: src - - regex: -DIRECTORY.TESTS: - - type: REQUIREMENT - - directory_name: tests - - regex: -DIRECTORY.EXAMPLES: - - type: REQUIREMENT - - directory_name: examples - - regex: -DIRECTORY.DOCS: - - type: REQUIREMENT - - directory_name: docs - - regex: -DIRECTORY.PAPERS: - - type: REQUIREMENT - - directory_name: papers +directory.interface_headers: + - type: Requirement +directory.implementation_headers: + - type: Requirement +directory.sources: + - type: Requirement +directory.tests: + - type: Requirement +directory.examples: + - type: Requirement +directory.docs: + - type: Requirement +directory.papers: + - type: Requirement # FILE -FILE.CPP_NAMES: - - type: RECOMMENDATION - - regex: -FILE.TEST_NAMES: - - type: REQUIREMENT - - regex: -FILE.LICENSE_ID: - - type: REQUIREMENT - - regex: [ - "// SPDX-License-Identifier: ", - "# SPDX-License-Identifier: ", - "" - ] -FILE.COPYRIGHT: - - type: RECOMMENDATION - - regex: +file.cpp_names: + - type: Recommendation +file.test_names: + - type: Requirement +file.license_id: + - type: Requirement +file.copyright: + - type: Recommendation # CPP -CPP.NAMESPACE: - - type: RECOMMENDATION -CPP.NO_FLAG_FORKING: - - type: REQUIREMENT -CPP.EXTENSION_IDENTIFIERS: - - type: RECOMMENDATION +cpp.namespace: + - type: Recommendation +cpp.no_flag_forking: + - type: Requirement +cpp.extension_identifiers: + - type: Recommendation diff --git a/infra/tools/beman-tidy/beman_tidy/LICENSE b/infra/tools/beman-tidy/beman_tidy/LICENSE new file mode 100644 index 0000000..f6db814 --- /dev/null +++ b/infra/tools/beman-tidy/beman_tidy/LICENSE @@ -0,0 +1,219 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py index f3431ab..8e7cfd6 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py @@ -1,10 +1,16 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from abc import ABC, abstractmethod +from abc import ABC from pathlib import Path from ..system.registry import get_beman_standard_check_name_by_class +from ...utils.string import ( + red_color, + yellow_color, + gray_color, + no_color, +) class BaseCheck(ABC): @@ -12,6 +18,10 @@ class BaseCheck(ABC): Base class for checks. This class is not meant to be used directly, it's meant to be subclassed. e.g., check for repository name, check for changelog, check for license, etc. + + + Notes: If should_skip() is True, check()/fix() are not called, + thus an implementation is not required in the derived class. """ def __init__(self, repo_info, beman_standard_check_config, name=None): @@ -19,7 +29,7 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): Create a new check instance. """ - # check name - e.g. "README.TITLE" + # check name - e.g. "readme.title" self.name = ( name if name is not None @@ -30,21 +40,39 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): ) # save the check config - self.config = beman_standard_check_config[self.name] + self.config = ( + beman_standard_check_config[self.name] + if "internal." not in self.name + else None + ) - # set type - e.g. "REQUIREMENT" or "RECOMMENDATION" - self.type = beman_standard_check_config[self.name]["type"] - assert self.type in ["REQUIREMENT", "RECOMMENDATION"], ( + # set type - e.g. "Requirement" or "Recommendation" + self.type = ( + beman_standard_check_config[self.name]["type"] + if "internal." not in self.name + else "Requirement" + ) + assert self.type in ["Requirement", "Recommendation"], ( f"Invalid check type: {self.type} for check = {self.name}." ) # set full text body - e.g. "The README.md should begin ..." - self.full_text_body = beman_standard_check_config[self.name]["full_text_body"] + self.full_text_body = ( + beman_standard_check_config[self.name]["full_text_body"] + if "internal." not in self.name + else "" + ) assert self.full_text_body is not None - # set log level - e.g. "ERROR" or "WARNING" - self.log_level = "ERROR" if self.type == "REQUIREMENT" else "WARNING" + # set log level - e.g. "error" or "warning" or "skipped" self.log_enabled = False + self.log_level = ( + "skipped" + if self.should_skip() + else "error" + if self.type == "Requirement" + else "warning" + ) # set repo info self.repo_info = repo_info @@ -58,12 +86,19 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): # set beman library maturity model beman_library_maturity_model = beman_standard_check_config[ - "README.LIBRARY_STATUS" + "readme.library_status" ] assert "values" in beman_library_maturity_model assert len(beman_library_maturity_model["values"]) == 4 self.beman_library_maturity_model = beman_library_maturity_model["values"] + def should_skip(self): + """ + Returns True if the check should be skipped. + If should_skip(), the pipeline will skip the check and not run pre_check(), check() and fix(). + """ + return False + def pre_check(self): """ Pre-checks if this rule is properly initialized. @@ -85,35 +120,59 @@ def pre_check(self): return True - @abstractmethod def check(self): """ Checks if the Beman Standard check is already applied. - If it's applied, this method should return True. - Otherwise, it returns False and self.fix() must be able to fix the issue. - Note: This methods must be always implemented. + Note: This method must be implemented in the derived class only if should_skip() is False. """ - pass + assert False, ( + "This method must be implemented in the derived class if should_skip() is False." + ) - @abstractmethod def fix(self): """ Fixes the issue if the Beman Standard is not applied. - If check already applied, this method is a no-op and should return True. - Otherwise, it will try to apply the check inplace. Returns the status of the fix attempt. - Note: The subclasses might not implement more than a stub if the fix method + Note: This method must be implemented in the derived class only if should_skip() is False. + The subclasses might not implement more than a stub if the fix method is too difficult to implement or does not make sense. """ - pass + assert False, ( + "This method must be implemented in the derived class if should_skip() is False." + ) + + def convert_to_requirement(self): + """ + Converts the check from Recommendation to Requirement. + """ + assert self.type == "Recommendation", ( + f"Cannot convert check {self.name} to Requirement." + ) + self.type = "Requirement" + self.log_level = "error" - def log(self, message, enabled=True): + def log(self, message, enabled=True, log_level=None): """ Logs a message with the check's log level. - e.g. [WARN][REPOSITORY.NAME]: The name "${name}" should be snake_case.' - e.g. [ERROR][TOPLEVEL.CMAKE]: Missing top level CMakeLists.txt.' + e.g. [WARN][repository.name]: The name "${name}" should be snake_case.' + e.g. [error][toplevel.cmake]: Missing top level CMakeLists.txt.' """ if self.log_enabled and enabled: - print(f"[{self.log_level:<15}][{self.name:<25}]: {message}") + log_level = log_level if log_level else self.log_level + color = ( + red_color + if log_level == "error" + else yellow_color + if log_level == "warning" + else gray_color + if log_level == "skipped" + else no_color + ) + + print(f"[{color}{log_level:<15}{no_color}][{self.name:<25}]: {message}") diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py index 49d9d24..de9c32b 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py @@ -3,7 +3,7 @@ from ..base.file_base_check import FileBaseCheck -# [CMAKE.*] checks category. +# [cmake.*] checks category. # All checks in this file extend the CMakeBaseCheck class. # # Note: CMakeBaseCheck is not a registered check! @@ -14,34 +14,34 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "CMakeLists.txt") -# TODO CMAKE.DEFAULT +# TODO cmake.default -# TODO CMAKE.USE_FETCH_CONTENT +# TODO cmake.use_fetch_content -# TODO CMAKE.PROJECT_NAME +# TODO cmake.project_name -# TODO CMAKE.PASSIVE_PROJECTS +# TODO cmake.passive_projects -# TODO CMAKE.LIBRARY_NAME +# TODO cmake.library_name -# TODO CMAKE.LIBRARY_ALIAS +# TODO cmake.library_alias -# TODO CMAKE.TARGET_NAMES +# TODO cmake.target_names -# TODO CMAKE.PASSIVE_TARGETS +# TODO cmake.passive_targets -# TODO CMAKE.SKIP_TESTS +# TODO cmake.skip_tests -# TODO CMAKE.SKIP_EXAMPLES +# TODO cmake.skip_examples -# TODO CMAKE.AVOID_PASSTHROUGHS +# TODO cmake.avoid_passthroughs diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py index 6868f23..8d493ae 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# [CPP.*] checks category. +# [cpp.*] checks category. -# TODO CPP.NAMESPACE +# TODO cpp.namespace -# TODO CPP.NO_FLAG_FORKING +# TODO cpp.no_flag_forking -# TODO CPP.EXTENSION_IDENTIFIERS +# TODO cpp.extension_identifiers diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index d533bb3..7a7f32d 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -5,10 +5,21 @@ from ..system.registry import register_beman_standard_check -# [DIRECTORY.*] checks category. +# [directory.*] checks category. +# All checks in this file extend the DirectoryBaseCheck class. +# +# Note: DirectoryBaseCheck is not a registered check! class BemanTreeDirectoryCheck(DirectoryBaseCheck): """ - Check if the directory tree is a Beman tree. + Beman tree: ${prefix_path}/beman/${short_name}. + Available via member: self.path + + Examples for a repo named "exemplar": + - include/beman/exemplar + - tests/beman/exemplar + - src/beman/exemplar + + Note: A path can be optional. Actual implementation will be in the derived's check(). """ def __init__(self, repo_info, beman_standard_check_config, prefix_path): @@ -19,39 +30,310 @@ def __init__(self, repo_info, beman_standard_check_config, prefix_path): ) -# TODO DIRECTORY.INTERFACE_HEADERS +# TODO directory.interface_headers -# TODO DIRECTORY.IMPLEMENTATION_HEADERS +# TODO directory.implementation_headers -# TODO DIRECTORY.SOURCES -@register_beman_standard_check("DIRECTORY.SOURCES") +@register_beman_standard_check("directory.sources") class DirectorySourcesCheck(BemanTreeDirectoryCheck): """ Check if the sources directory is src/beman/. + Note: Allow header-only libraries (missing any source files location). + + Example for a repo named "exemplar": src/beman/exemplar """ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "src") + def pre_check(self): + # Need to override this, because directory.sources is conditional + # (a repo without any source files location is still valid - header only libraries) + return True + + def check(self): + # TODO: This is a temporary implementation. Use CMakeLists.txt to actually get the source files location. + # Should not allow other known source locations. + forbidden_source_locations = ["source/", "sources/", "lib/", "library/"] + for forbidden_prefix in forbidden_source_locations: + forbidden_prefix = self.repo_path / forbidden_prefix + if forbidden_prefix.exists(): + self.log( + f"Please move source files from {forbidden_prefix} to src/beman/{self.repo_name}. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorysources for more information." + ) + return False + + # If `src/` exists, src/beman/ also should exist. + if (self.repo_path / "src/").exists() and not self.path.exists(): + self.log( + f"Please use the required source files location: src/beman/{self.repo_name}. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorysources for more information." + ) + return False + + # Valid source file location or missing -> Beman Standard compliant. + return True + + def fix(self): + # Because we don't know which is the actually invalid source file locations, + # we cannot do a proper implementation for fix(). + if not self.check(): + self.log( + f"Please manually move sources to src/beman/{self.repo_name}. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorysources for more information." + ) + + +@register_beman_standard_check("directory.tests") +class DirectoryTestsCheck(BemanTreeDirectoryCheck): + """ + Check if all test files reside within tests/beman/ directory. + Examples: + tests + └── beman + └── exemplar + └── identity.test.cpp + + tests + └── beman + └── optional + ├── CMakeLists.txt + ├── detail + | └── iterator.test.cpp + ├── optional.test.cpp + ├── optional_constexpr.test.cpp + ├── optional_monadic.test.cpp + ├── optional_range_support.test.cpp + ├── test_types.cpp + ├── test_types.hpp + ├── test_utilities.cpp + └── test_utilities.hpp + """ + + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "tests") + def check(self): - return self.pre_check() + # Exclude directories that are not part of the tests. + exclude_dirs = [".github", "tests"] + if self.repo_name == "exemplar": + exclude_dirs.extend(["cookiecutter", "infra"]) + + # Find all test files in the repository outside the excluded directories. + misplaced_test_files = [] + for p in self.repo_path.rglob("*test*"): + if not any(excluded in str(p) for excluded in exclude_dirs): + misplaced_test_files.append(p) + + # Check if any test files are misplaced outside the excluded directories. + if len(misplaced_test_files) > 0: + for misplaced_test_file in misplaced_test_files: + self.log(f"Misplaced test file found: {misplaced_test_file}") + + self.log( + "Please move all test files within the tests/ directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorytests for more information." + ) + return False + + # Check if the repository has at least one relevant test inside tests/beman/. + relevant_test_files = list(self.path.rglob("*.test.*")) + relevant_cmake_files = list(self.path.rglob("CMakeLists.txt")) + + if len(relevant_test_files) == 0 or len(relevant_cmake_files) == 0: + self.log( + "Missing relevant test files in tests/ directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorytests for more information." + ) + return False + + # Check passes if tests/ directory exists and contains relevant test files. + return True def fix(self): + self.log( + "Please manually move test files to the tests/beman/ directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorytests for more information." + ) + + +@register_beman_standard_check("directory.examples") +class DirectoryExamplesCheck(DirectoryBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "examples") + + def check(self): """ - TODO: Implement the fix. + All example files must reside within the top-level examples/ directory. Each project must have at least one relevant example. + Tree Example: + examples/ + ├── CMakeLists.txt + ├── identity_as_default_projection.cpp + └── identity_direct_usage.cpp """ - pass + # Check if the examples/ directory contains at least one relevant example. + if len(list(self.path.glob("**/*.cpp"))) == 0: + self.log( + "Missing one relevant example - cannot find examples/**/*.cpp. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directoryexamples for more information." + ) + return False + if len(list(self.path.glob("**/*CMakeLists.txt"))) == 0: + self.log( + "Missing CMakeLists.txt for examples - cannot find examples/**/*CMakeLists.txt. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directoryexamples for more information." + ) + return False -# TODO DIRECTORY.TESTS + # Check passes if the examples/ directory exists and contains at least one relevant example. + return True + def fix(self): + self.log( + "Please add a relevant example to the examples/ directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directoryexamples for more information." + ) -# TODO DIRECTORY.EXAMPLES +@register_beman_standard_check("directory.docs") +class DirectoryDocsCheck(DirectoryBaseCheck): + """ + Check if the all documentation files reside within docs/ directory. + Exception: root README.md file. + """ + + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "docs") + + def pre_check(self): + # Need to override this, because directory.docs is conditional + # (a repo without any documentation is still valid). + return True + + def check(self): + # Exclude directories that are not part of the documentation. + exclude_dirs = ["src", "papers", "examples", ".github"] + if self.path.exists(): + exclude_dirs.append("docs") + if self.repo_name == "exemplar": + exclude_dirs.extend(["cookiecutter", "infra"]) + + # Find all MD files in the repository. + misplaced_md_files = [ + p + for p in self.repo_path.rglob("*.md") + if not any( + excluded in p.parts for excluded in exclude_dirs + ) # exclude files in excluded directories + and p != self.repo_path / "README.md" # exclude root README.md + ] + + # Check if any MD files are misplaced. + if len(misplaced_md_files) > 0: + for misplaced_md_file in misplaced_md_files: + self.log(f"Misplaced MD file found: {misplaced_md_file}") -# TODO DIRECTORY.DOCS + self.log( + "Please move all documentation files within the docs/ directory, except for the root README.md file. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorydocs for more information." + ) + return False + + # Check passes if there is no docs/ directory or no misplaced MD files are found + return True + + def fix(self): + self.log( + "Please manually move documentation files to the docs/ directory, except for the root README.md file. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorydocs for more information." + ) + + +@register_beman_standard_check("directory.papers") +class DirectoryPapersCheck(DirectoryBaseCheck): + """ + Check if the all paper related files reside within papers/ directory. + """ -# TODO DIRECTORY.PAPERS + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "papers") + + def pre_check(self): + # Need to override this, because directory.papers is conditional + # (a repo without any paper files is still valid - no papers/ directory required) + return True + + def check(self): + """ + If present, all paper related files (e.g., WIP LaTeX/Markdown projects for ISO Standardization), must reside within the top-level papers/ directory. + Tree Example: + papers/ + └── P2988 + ├── Makefile + ├── README.md + └── abstract.bst + """ + # Exclude directories that are not part of the papers/ directory. + exclude_dirs = ["src", "docs", "examples", ".github"] + if self.path.exists(): + exclude_dirs.append("papers") + if self.repo_name == "exemplar": + exclude_dirs.extend(["cookiecutter", "infra"]) + + # File extensions that are considered "paper-related" + paper_extensions = [ + ".md", + ".bib", + ".bst", + ".tex", + ".sty", + ".cls", + ".pdf", + ".docx", + ".org", + ".html", + ".css", + ".js", + ".asciidoc", + ".asc", + ".ad", + ".ascdoc", + ".rst", + ".wip", + ".draft", + ".proposal", + ".standard", + ] + + # Find all misplaced paper-related files in the repository. + misplaced_paper_files = [] + for extension in paper_extensions: + for p in self.repo_path.rglob(f"*{extension}"): + # Exclude files that are already in excluded directories. + if ( + not any(excluded in str(p) for excluded in exclude_dirs) + and p != self.repo_path / "README.md" + ): + misplaced_paper_files.append(p) + + if len(misplaced_paper_files) > 0: + for misplaced_paper_file in misplaced_paper_files: + self.log(f"Misplaced paper file found: {misplaced_paper_file}") + + self.log( + "Please move all paper related files (and directories if applicable) within the papers/ directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorypapers for more information." + ) + + return False + + # Check passes if there is no papers/ directory and no misplaced paper files are found + return True + + def fix(self): + self.log( + "Please move all paper related files (and directories if applicable) to papers/ directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#directorypapers for more information." + ) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py index b66e8be..34c1104 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py @@ -1,19 +1,19 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# [FILE.*] checks category. +# [file.*] checks category. # All checks in this file extend the FileBaseCheck class. # # Note: FileBaseCheck is not a registered check! -# TODO FILE.NAMES +# TODO file.names -# TODO FILE.TEST_NAMES +# TODO file.test_names -# TODO FILE.LICENSE_ID +# TODO file.license_id -# TODO FILE.COPYRIGHT +# TODO file.copyright diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py index d084753..1b10d61 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py @@ -1,7 +1,26 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# TODO LIBRARY.NAMES -# TODO REPOSITORY.NAME -# TODO REPOSITORY.CODEOWNERS -# TODO REPOSITORY.DISALLOW_GIT_SUBMODULES +from ..base.base_check import BaseCheck +from ..system.registry import register_beman_standard_check + + +# General checks category. +# All checks in this file extend the BaseCheck class. +# +# Note: BaseCheck is not a registered check! + + +@register_beman_standard_check("library.name") +class LibraryNameCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def should_skip(self): + # Cannot actually implement library.name, so skip it. + # No need to run pre_check() and check() as well, as they are not implemented. + self.log( + "beman-tidy cannot actually check library.name. Please ignore this message if cmake.library_name and repository.name have passed. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#libraryname for more information." + ) + return True diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 6eb75ab..cd1f978 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -1,9 +1,19 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import filecmp + +from ..base.base_check import BaseCheck from ..base.file_base_check import FileBaseCheck +from ..system.registry import register_beman_standard_check +from beman_tidy.lib.utils.git import get_beman_recommendated_license_path +from beman_tidy.lib.utils.string import ( + match_apache_license_v2_with_llvm_exceptions, + match_boost_software_license_v1_0, + match_the_mit_license, +) -# [LICENSE.*] checks category. +# [license.*] checks category. # All checks in this file extend the LicenseBaseCheck class. # # Note: LicenseBaseCheck is not a registered check! @@ -14,10 +24,80 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "LICENSE") -# TODO LICENSE.APPROVED +@register_beman_standard_check("license.approved") +class LicenseApprovedCheck(LicenseBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + content = self.read() + + if match_apache_license_v2_with_llvm_exceptions(content): + self.log( + "Valid Apache License - Version 2.0 with LLVM Exceptions found in LICENSE file.", + log_level="info", + ) + return True + + if match_boost_software_license_v1_0(content): + self.log( + "Valid Boost Software License - Version 1.0 found in LICENSE file.", + log_level="info", + ) + return True + + if match_the_mit_license(content): + self.log("Valid MIT License found in LICENSE file.", log_level="info") + return True + + self.log( + "Invalid license - cannot find approved license in LICENSE file. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licenseapproved for more information." + ) + return False + def fix(self): + self.log( + "Please update the LICENSE file to include an approved license. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licenseapproved for more information." + ) -# TODO LICENSE.APACHE_LLVM +@register_beman_standard_check("license.apache_llvm") +class LicenseApacheLLVMCheck(LicenseBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + # Compare LICENSE file stored at self.path with the reference one. + target_license = self.path + ref_license = get_beman_recommendated_license_path() + if not filecmp.cmp(target_license, ref_license, shallow=False): + self.log( + "Please update the LICENSE file to include the Apache License v2.0 with LLVM Exceptions. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licenseapache_llvm for more information." + ) + return False + + return True + + def fix(self): + self.log( + "Please update the LICENSE file to include the Apache License v2.0 with LLVM Exceptions. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licenseapache_llvm for more information." + ) + + +@register_beman_standard_check("license.criteria") +class LicenseCriteriaCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) -# TODO LICENSE.CRITERIA + def should_skip(self): + # Cannot actually implement license.criteria, so skip it. + # No need to run pre_check() and check() as well, as they are not implemented. + self.log( + "beman-tidy cannot actually check license.criteria. Please ignore this message if license.approved has passed. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#licensecriteria for more information." + ) + return True diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index fcbead6..04a92e3 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -3,21 +3,39 @@ import re -from ..base.file_base_check import FileBaseCheck +from ..base.file_base_check import FileBaseCheck, BaseCheck from ..system.registry import register_beman_standard_check +from beman_tidy.lib.utils.string import ( + match_apache_license_v2_with_llvm_exceptions, + match_boost_software_license_v1_0, + match_the_mit_license, +) -# [README.*] checks category. + +# [readme.*] checks category. # All checks in this file extend the ReadmeBaseCheck class. # # Note: ReadmeBaseCheck is not a registered check! - - class ReadmeBaseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "README.md") -@register_beman_standard_check("README.TITLE") +@register_beman_standard_check("readme.purpose") +class ReadmePurposeCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def should_skip(self): + # Cannot actually implement readme.purpose, thus skip it. + self.log( + "beman-tidy cannot actually check readme.purpose. Please add a one line summary describing the library's purpose." + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmepurpose." + ) + return True + + +@register_beman_standard_check("readme.title") class ReadmeTitleCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) @@ -45,40 +63,88 @@ def fix(self): return True -@register_beman_standard_check("README.BADGES") +@register_beman_standard_check("readme.badges") class ReadmeBadgesCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): """ - self.config["values"] contains a fixed set of Beman badges. + self.config["values"] contains a fixed set of Beman badges, + check .beman-standard.yml for the desired format. """ - badges = self.config["values"] - assert len(badges) == 4 # The number of library maturity model states - # Check if exactly one of the required badges is present. - badge_count = len([badge for badge in badges if self.has_content(badge)]) - if badge_count != 1: - self.log( - f"The file '{self.path}' does not contain exactly one of the required badges from {badges}" - ) - return False + def validate_badges(category, badges): + if category == "library_status": + assert len(badges) == 4 # The number of library maturity model states. + elif category == "standard_target": + assert ( + len(badges) == 2 + ) # The number of standard targets specified in the Beman Standard. - return True + def count_badges(badges): + return len([badge for badge in badges if self.has_content(badge)]) + + count_failed = 0 + for category_data in self.config["values"]: + category = list(category_data.keys())[0] + badges = category_data[category] + validate_badges(category, badges) + + if count_badges(badges) != 1: + self.log( + f"The file '{self.path}' does not contain exactly one required badge of category '{category}'." + ) + count_failed += 1 + + return count_failed == 0 def fix(self): - # TODO: Implement the fix. - pass + self.log( + "Please add required badges in README.md file. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmebadges for the desired format." + ) + return True -# TODO README.PURPOSE +@register_beman_standard_check("readme.implements") +class ReadmeImplementsCheck(ReadmeBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + def check(self): + lines = self.read_lines_strip() -# TODO README.IMPLEMENTS + # Match the pattern to start with "Implements:" and then have a paper reference and a wg21.link URL. + # Examples of valid lines: + # **Implements**: [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + # **Implements**: [Give *std::optional* Range Support (P3168R2)](https://wg21.link/P3168R2) and [`std::optional` (P2988R5)](https://wg21.link/P2988R5) + # **Implements**: [.... (PxyzwRr)](https://wg21.link/PxyzwRr), [.... (PabcdRr)](https://wg21.link/PabcdRr), and [.... (PijklRr)](https://wg21.link/PijklRr), + regex = r"^\*\*Implements\*\*:\s+.*\bP\d{4}R\d+\b.*wg21\.link/\S+" + + # Count how many lines match the regex + implement_lines = 0 + for line in lines: + if re.match(regex, line): + implement_lines += 1 + + # If there is exactly one "Implements:" line, it is valid + if implement_lines == 1: + return True + + # Invalid/missing/duplicate "Implements:" line + self.log( + f"Invalid/missing/duplicate 'Implements:' line in '{self.path}'. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmeimplements for more information." + ) + return False + + def fix(self): + self.log( + "Please write a Implements line in README.md file. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmeimplements for the desired format." + ) + return True -@register_beman_standard_check("README.LIBRARY_STATUS") +@register_beman_standard_check("readme.library_status") class ReadmeLibraryStatusCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) @@ -101,5 +167,47 @@ def check(self): return True def fix(self): - # TODO: Implement the fix. - pass + self.log( + "Please write a Status line in README.md file. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmelibrary_status for the desired format." + ) + return True + + +@register_beman_standard_check("readme.license") +class ReadmeLicenseCheck(ReadmeBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + # Extract ## License section from the file. + content = self.read() + license_section = re.search( + r"^## License\n(.*?)\n##", content, re.DOTALL | re.MULTILINE + ) + if license_section is None: + self.log( + f"The file '{self.path}' does not contain a `## License` section. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmelicense." + ) + return False + + # Check if the license section contains at least one of the required licenses. + license_text = license_section.group(1).strip() + if ( + not match_apache_license_v2_with_llvm_exceptions(license_text) + and not match_boost_software_license_v1_0(license_text) + and not match_the_mit_license(license_text) + ): + self.log( + f"The file '{self.path}' does not contain the required license. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmelicense for the desired format." + ) + return False + + return True + + def fix(self): + self.log( + "Please write a License section in README.md file. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#readmelicense for the desired format." + ) + return True diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py index 6c2f59b..ac33a24 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py @@ -1,15 +1,72 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# [RELEASE.*] checks category. +import re +from beman_tidy.lib.checks.base.base_check import BaseCheck +from beman_tidy.lib.checks.beman_standard.readme import ReadmeBaseCheck +from ..system.registry import register_beman_standard_check + +# [release.*] checks category. # Note: Data is stored online - e.g. https://github.com/bemanproject/exemplar/releases -# TBD - Do we want to implement these checks? +# beman-tidy is an offline tool, so it cannot check these issues, +# but for some of them it will try some heuristics. + + +@register_beman_standard_check("release.github") +class ReleaseGithubCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def should_skip(self): + # Cannot actually implement release.github, thus skip it. + self.log( + "beman-tidy cannot actually check release.github. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#releasegithub." + ) + return True + + +@register_beman_standard_check("release.notes") +class ReleaseNotesCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def should_skip(self): + # Cannot actually implement release.notes, thus skip it. + self.log( + "beman-tidy cannot actually check release.notes. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#releasenotes." + ) + return True + +@register_beman_standard_check("release.godbolt_trunk_version") +class ReleaseGodboltTrunkVersionCheck(ReadmeBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) -# TODO RELEASE.GITHUB + def check(self): + """ + Check that the Godbolt badge is present in the root README.md file. + If present, this assumes that the trunk version is available on Godbolt. + e.g. [![Compiler Explorer Example](https://img.shields.io/badge/Try%20it%20on%20Compiler%20Explorer-grey?logo=compilerexplorer&logoColor=67c52a)](https://godbolt.org/z/Gc6Y9j6zf) + Note: Only the suffix of the https://godbolt.org/z/* has dynamic content. + """ -# TODO RELEASE.NOTES + content = self.read() + regex = re.compile( + r"\[!\[Compiler Explorer Example\]\(https://img\.shields\.io/badge/Try%20it%20on%20Compiler%20Explorer-grey\?logo=compilerexplorer&logoColor=67c52a\)\]\(https://godbolt\.org/z/([a-zA-Z0-9]+)\)" + ) + if not re.search(regex, content): + self.log( + f"The file '{self.path}' does not contain a Compiler Explorer badge - trunk version assumed to be missing." + ) + return False + return True -# TODO RELEASE.GODBOLT_TRUNK_VERSION + def fix(self): + self.log( + "beman-tidy cannot fix this issue. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#releasegodbolt_trunk_version." + ) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py new file mode 100644 index 0000000..f2b4abc --- /dev/null +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import re +import textwrap + +from ..base.file_base_check import FileBaseCheck +from ..base.base_check import BaseCheck +from ..system.registry import register_beman_standard_check +from ...utils.string import is_beman_snake_case + +# [repository.*] checks category. +# All checks in this file extend the FileBaseCheck class. +# +# Note: FileBaseCheck is not a registered check! + + +@register_beman_standard_check("repository.name") +class RepositoryNameCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + repo_name = self.repo_info["name"] + if not is_beman_snake_case(repo_name): + self.log( + "The repository should be named after the library name excluding the 'beman.' prefix. It should not contain a target C++ version. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositoryname for more information." + ) + return False + + return True + + def fix(self): + self.log( + "beman-tidy can't automatically fix the repository name. " + "Please see https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositoryname for more information." + ) + pass + + +@register_beman_standard_check("repository.default_branch") +class RepositoryDefaultBranchCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + default_branch = self.repo_info["default_branch"] + if default_branch != "main": + self.log(f"Invalid default branch in repo: {default_branch} vs 'main'.") + return False + + return True + + def fix(self): + self.log( + "Please set `main` as default branch in the repository. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositorydefault_branch for more information." + ) + + +@register_beman_standard_check("repository.codeowners") +class RepositoryCodeownersCheck(FileBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, ".github/CODEOWNERS") + + def check(self): + # Since this class simply checks for the existence of a CODEOWNERS file, + # there's nothing more to do than the default pre-check. + return super().pre_check() + + def fix(self): + self.log( + "Please add a CODEOWNERS file to the repository. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositorycodeowners for more information." + ) + + +@register_beman_standard_check("repository.code_review_rules") +class RepositoryCodeReviewRulesCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def should_skip(self): + # Cannot actually implement repository.code_review_rules, thus skip it. + self.log( + "beman-tidy cannot actually check repository.code_review_rules. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositorycode_review_rules." + ) + return True + + +@register_beman_standard_check("repository.disallow_git_submodules") +class RepositoryDisallowGitSubmodulesCheck(FileBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, ".gitmodules") + + def pre_check(self): + # Need to override this, because repository.disallow_git_submodules is conditional + return True + + def check(self): + if self.path.exists(): + content = self.read() + + # Regex pattern to match "wg21" submodule + regex = re.compile( + textwrap.dedent(r""" + ^\[submodule \"(?:.+?/)?wg21\"] + \tpath = papers/(.+?) + \turl = https://github.com/mpark/wg21.git$ + """).strip() + ) + + if not regex.match(content): + self.log( + "The repository should not use git submodules. Please remove them. " + "Known exception: wg21. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositorydisallow_git_submodules for more information." + ) + return False + + # Check passes if .gitmodules file doesn't exist or if it only contains wg21 submodule. + return True + + def fix(self): + self.log( + "beman-tidy can't automatically fix the repository submodules. " + "See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#repositorydisallow_git_submodules for more information." + ) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index f4c4ad3..04f2edf 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -6,52 +6,55 @@ from .readme import ReadmeBaseCheck from ..system.registry import register_beman_standard_check -# [TOPLEVEL.*] checks category. +# [toplevel.*] checks category. # All checks in this file extend the ToplevelBaseCheck class. # # Note: ToplevelBaseCheck is not a registered check! -@register_beman_standard_check(check="TOPLEVEL.CMAKE") +@register_beman_standard_check("toplevel.cmake") class ToplevelCmakeCheck(CMakeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): + # Since this class simply checks for the existence of a CMakeLists.txt file, + # there's nothing more to do than the default pre-check. return super().pre_check() def fix(self): - # TODO: Implement the fix. - pass + self.log( + "Please add a CMakeLists.txt file to the repository. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#toplevelcmake for the desired format." + ) -@register_beman_standard_check("TOPLEVEL.LICENSE") +@register_beman_standard_check("toplevel.license") class ToplevelLicenseCheck(LicenseBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - # since this class simply checks for the existence of a LICENSE file, + # Since this class simply checks for the existence of a LICENSE file, # there's nothing more to do than the default pre-check. return super().pre_check() def fix(self): self.log( - "Please add a LICENSE file to the repository. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#license for more information." + "Please add a LICENSE file to the repository. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#toplevellicense for more information." ) -@register_beman_standard_check("TOPLEVEL.README") +@register_beman_standard_check("toplevel.readme") class ToplevelReadmeCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - # since this class simply checks for the existence of a README file, + # Since this class simply checks for the existence of a README file, # there's nothing more to do than the default pre-check. return super().pre_check() def fix(self): self.log( - "Please write a README file. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmemd for the desired format." + "Please write a README file. See https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#toplevelreadme for the desired format." ) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py index ecc1145..d826730 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py @@ -8,11 +8,13 @@ class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): """ - If fix is attempted, disallow it if there are unstaged changes. + --fix-inplace requires no unstaged changes. """ def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "NO_UNSTAGED_CHANGES") + super().__init__( + repo_info, beman_standard_check_config, "internal.no_unstaged_changes" + ) def check(self): """ @@ -25,6 +27,6 @@ def fix(self): Stop the program if there are unstaged changes. """ self.log( - "The fix cannot be applied inplace. Please commit or stash your changes. STOP." + "The --fix-inplace requires no unstaged changes. Please commit or stash your changes. STOP." ) sys.exit(1) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py index cabb8ac..6916eef 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py @@ -12,12 +12,12 @@ def register_beman_standard_check(check: str): Decorator to register a check class with a specific ID. Usage: - @register_beman_standard_check("README.TITLE") + @register_beman_standard_check("readme.title") class ReadmeTitleCheck(ReadmeBaseCheck): ... Notes: Only register most derived check classes, which are actually part from - The Beman Standard - e.g., README.TITLE, README.BADGES, etc. + The Beman Standard - e.g., readme.title, readme.badges, etc. """ def decorator(check_class: Type) -> Type: diff --git a/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py b/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py index a5d7d40..b160ea9 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -5,6 +5,13 @@ from .checks.system.registry import get_registered_beman_standard_checks from .checks.system.git import DisallowFixInplaceAndUnstagedChangesCheck +from .utils.string import ( + red_color, + green_color, + yellow_color, + gray_color, + no_color, +) # import all the implemented checks. # TODO: Consider removing F403 from ignored lint checks @@ -16,14 +23,9 @@ from .checks.beman_standard.license import * # noqa: F401, F403 from .checks.beman_standard.readme import * # noqa: F401, F403 from .checks.beman_standard.release import * # noqa: F401, F403 +from .checks.beman_standard.repository import * # noqa: F401, F403 from .checks.beman_standard.toplevel import * # noqa: F401, F403 -red_color = "\033[91m" -green_color = "\033[92m" -yellow_color = "\033[93m" -gray_color = "\033[90m" -no_color = "\033[0m" - def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): """ @@ -34,160 +36,226 @@ def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): @return: The number of failed checks. """ - """ - Helper function to log messages. - """ - def log(msg): + """ + Helper function to log messages. + """ if args.verbose: print(msg) - """ - Helper function to run a check. - @param check_class: The check class type to run. - @param log_enabled: Whether to log the check result. - @return: True if the check passed, False otherwise. - """ - - def run_check(check_class, log_enabled=args.verbose): + def run_check(check_class, log_enabled=args.verbose, require_all=args.require_all): + """ + Helper function to run a check. + @param check_class: The check class type to run. + @param log_enabled: Whether to log the check result. + @return: True if the check passed, False otherwise. + """ check_instance = check_class(args.repo_info, beman_standard_check_config) - check_instance.log_enabled = log_enabled - check_type = check_instance.type - log(f"Running check [{check_instance.type}][{check_instance.name}] ... ") + # Check if the check should be skipped, with logging disabled (by default). + if check_instance.should_skip(): + log(f"Running check [{check_instance.type}][{check_instance.name}] ... ") + check_instance.log_enabled = log_enabled + check_instance.should_skip() # Run should_skip() again, with logging enabled. + log( + f"Running check [{check_instance.type}][{check_instance.name}] ... {gray_color}skipped{no_color}\n" + ) + return check_instance.type, "skipped" + elif require_all and check_instance.type == "Recommendation": + # Convert the check to a requirement because --require-all is set. + check_instance.convert_to_requirement() + # Run the check on normal mode. + log(f"Running check [{check_instance.type}][{check_instance.name}] ... ") + check_instance.log_enabled = log_enabled if (check_instance.pre_check() and check_instance.check()) or ( args.fix_inplace and check_instance.fix() ): log( - f"\tcheck [{check_instance.type}][{check_instance.name}] ... {green_color}PASSED{no_color}\n" + f"\tcheck [{check_instance.type}][{check_instance.name}] ... {green_color}passed{no_color}\n" ) - return check_type, True + return check_instance.type, "passed" else: log( - f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}FAILED{no_color}\n" + f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}failed{no_color}\n" ) - return check_type, False - - """ - Main pipeline. - """ + return check_instance.type, "failed" def run_pipeline_helper(): + """ + Helper function to run the pipeline. + """ # Internal checks if args.fix_inplace: - run_check(DisallowFixInplaceAndUnstagedChangesCheck, log_enabled=False) + run_check(DisallowFixInplaceAndUnstagedChangesCheck, log_enabled=True) implemented_checks = get_registered_beman_standard_checks() all_checks = beman_standard_check_config - cnt_passed = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, + # All checks from the Beman Standard. + cnt_all_beman_standard_checks = { + "Requirement": 0, + "Recommendation": 0, } - cnt_failed = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, + # All checks from the Beman Standard that are implemented. + cnt_implemented_checks = { + "Requirement": 0, + "Recommendation": 0, } + # All checks from the Beman Standard that are not implemented. + cnt_not_implemented_checks = { + "Requirement": 0, + "Recommendation": 0, + } + # All implemented checks that passed. + cnt_passed_checks = { + "Requirement": 0, + "Recommendation": 0, + } + # All implemented checks that failed. + cnt_failed_checks = { + "Requirement": 0, + "Recommendation": 0, + } + # All implemented checks that were skipped (e.g., dummy implementation + # or it cannot be implemented). + cnt_skipped_checks = { + "Requirement": 0, + "Recommendation": 0, + } + + # Run the checks. for check_name in checks_to_run: if check_name not in implemented_checks: continue - check_type, passed = run_check(implemented_checks[check_name]) - if passed: - cnt_passed[check_type] += 1 + check_type, status = run_check(implemented_checks[check_name]) + if status == "passed": + cnt_passed_checks[check_type] += 1 + elif status == "failed": + cnt_failed_checks[check_type] += 1 + elif status == "skipped": + cnt_skipped_checks[check_type] += 1 else: - cnt_failed[check_type] += 1 + raise ValueError(f"Invalid status: {status}") - cnt_skipped = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - cnt_all_beman_standard_checks = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - cnt_implemented_checks = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } + # Count the checks from the Beman Standard. for check_name in all_checks: - check_type = all_checks[check_name]["type"] + check_type = ( + all_checks[check_name]["type"] + if not args.require_all + else "Requirement" + ) cnt_all_beman_standard_checks[check_type] += 1 if check_name not in implemented_checks: - cnt_skipped[check_type] += 1 + cnt_not_implemented_checks[check_type] += 1 else: cnt_implemented_checks[check_type] += 1 return ( - cnt_passed, - cnt_failed, - cnt_skipped, - cnt_implemented_checks, + cnt_passed_checks, + cnt_failed_checks, + cnt_skipped_checks, cnt_all_beman_standard_checks, + cnt_implemented_checks, + cnt_not_implemented_checks, ) log("beman-tidy pipeline started ...\n") ( - cnt_passed, - cnt_failed, - cnt_skipped, - cnt_implemented_checks, + cnt_passed_checks, + cnt_failed_checks, + cnt_skipped_checks, cnt_all_beman_standard_checks, + cnt_implemented_checks, + cnt_not_implemented_checks, ) = run_pipeline_helper() log("\nbeman-tidy pipeline finished.\n") # Always print the summary. print( - f"Summary REQUIREMENT: {green_color} {cnt_passed['REQUIREMENT']} checks PASSED{no_color}, {red_color}{cnt_failed['REQUIREMENT']} checks FAILED{no_color}, {gray_color}{cnt_skipped['REQUIREMENT']} skipped (NOT implemented).{no_color}" + f"Summary Requirement: {green_color} {cnt_passed_checks['Requirement']} checks passed{no_color}, {red_color}{cnt_failed_checks['Requirement']} checks failed{no_color}, {gray_color}{cnt_skipped_checks['Requirement']} checks skipped, {no_color} {cnt_not_implemented_checks['Requirement']} checks not implemented." ) print( - f"Summary RECOMMENDATION: {green_color} {cnt_passed['RECOMMENDATION']} checks PASSED{no_color}, {red_color}{cnt_failed['RECOMMENDATION']} checks FAILED{no_color}, {gray_color}{cnt_skipped['RECOMMENDATION']} skipped (NOT implemented).{no_color}" + f"Summary Recommendation: {green_color} {cnt_passed_checks['Recommendation']} checks passed{no_color}, {red_color}{cnt_failed_checks['Recommendation']} checks failed{no_color}, {gray_color}{cnt_skipped_checks['Recommendation']} checks skipped, {no_color} {cnt_not_implemented_checks['Recommendation']} checks not implemented." ) # Always print the coverage. + cnt_passed_requirement = ( + cnt_passed_checks["Requirement"] + cnt_skipped_checks["Requirement"] + if not args.require_all + else cnt_passed_checks["Requirement"] + + cnt_skipped_checks["Requirement"] + + cnt_passed_checks["Recommendation"] + + cnt_skipped_checks["Recommendation"] + ) + total_implemented_requirement = ( + cnt_implemented_checks["Requirement"] + cnt_implemented_checks["Recommendation"] + if not args.require_all + else cnt_implemented_checks["Requirement"] + ) coverage_requirement = round( - cnt_passed["REQUIREMENT"] / cnt_implemented_checks["REQUIREMENT"] * 100, 2 + cnt_passed_requirement / total_implemented_requirement * 100, + 2, ) - coverage_recommendation = round( - cnt_passed["RECOMMENDATION"] / cnt_implemented_checks["RECOMMENDATION"] * 100, 2 + cnt_passed_recommendation = ( + cnt_passed_checks["Recommendation"] + cnt_skipped_checks["Recommendation"] + if not args.require_all + else 0 ) - total_passed = cnt_passed["REQUIREMENT"] + cnt_passed["RECOMMENDATION"] - total_implemented = ( - cnt_implemented_checks["REQUIREMENT"] + cnt_implemented_checks["RECOMMENDATION"] + total_implemented_recommendation = ( + cnt_implemented_checks["Recommendation"] if not args.require_all else 0 ) + coverage_recommendation = ( + round( + cnt_passed_recommendation / total_implemented_recommendation * 100, + 2, + ) + if total_implemented_recommendation > 0 + else 0 + ) + total_passed = ( + cnt_passed_checks["Requirement"] + + cnt_passed_checks["Recommendation"] + + cnt_skipped_checks["Requirement"] + + cnt_skipped_checks["Recommendation"] + ) + total_implemented = total_implemented_requirement + total_implemented_recommendation total_coverage = round((total_passed) / (total_implemented) * 100, 2) print( - f"\n{__calculate_coverage_color(coverage_requirement)}Coverage REQUIREMENT: {coverage_requirement:{6}.2f}% ({cnt_passed['REQUIREMENT']}/{cnt_implemented_checks['REQUIREMENT']} checks passed).{no_color}" + f"\n{calculate_coverage_color(coverage_requirement)}Coverage Requirement: {coverage_requirement:{6}.2f}% ({cnt_passed_requirement}/{total_implemented_requirement} checks passed).{no_color}" ) - if args.require_all: - print( - f"{__calculate_coverage_color(coverage_recommendation)}Coverage RECOMMENDATION: {coverage_recommendation:{6}.2f}% ({cnt_passed['RECOMMENDATION']}/{cnt_implemented_checks['RECOMMENDATION']} checks passed).{no_color}" - ) - print( - f"{__calculate_coverage_color(total_coverage)}Coverage TOTAL: {total_coverage:{6}.2f}% ({total_passed}/{total_implemented} checks passed).{no_color}" - ) - else: - print("Note: RECOMMENDATIONs are not included (--require-all NOT set).") - total_cnt_failed = cnt_failed["REQUIREMENT"] + ( - cnt_failed["RECOMMENDATION"] if args.require_all else 0 + print( + f"{calculate_coverage_color(coverage_recommendation, no_color=args.require_all)}Coverage Recommendation: {coverage_recommendation:{6}.2f}% ({cnt_passed_recommendation}/{total_implemented_recommendation} checks passed).{no_color}" + ) + print( + f"{calculate_coverage_color(total_coverage)}Coverage TOTAL: {total_coverage:{6}.2f}% ({total_passed}/{total_implemented} checks passed).{no_color}" + ) + # else: + # print("Note: RECOMMENDATIONs are not included (--require-all NOT set).") + total_cnt_failed = cnt_failed_checks["Requirement"] + ( + cnt_failed_checks["Recommendation"] if args.require_all else 0 ) sys.stdout.flush() return total_cnt_failed -def __calculate_coverage_color(cov): +def calculate_coverage_color(coverage, no_color=False): """ Returns the colour for the coverage print based on severity Green for 100% Red for 0% Yellow for anything else + + Exception: If no_color is True, the color will be removed. """ - if cov == 100: + if no_color: + return gray_color + elif coverage == 100: return green_color - elif cov == 0: + elif coverage == 0: return red_color else: return yellow_color diff --git a/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py b/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py index 7f8e3d8..a37e362 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -33,6 +33,10 @@ def get_repo_info(path: str): # Get the current branch current_branch = repo.active_branch.name + # Get the default branch + split_head = repo.git.symbolic_ref("refs/remotes/origin/HEAD").split("/") + default_branch = split_head[-1] + # Get the commit hash commit_hash = repo.head.commit.hexsha @@ -47,6 +51,7 @@ def get_repo_info(path: str): "name": repo_name, "remote_url": remote_url, "current_branch": current_branch, + "default_branch": default_branch, "commit_hash": commit_hash, "status": status, "unstaged_changes": unstaged_changes, @@ -66,6 +71,13 @@ def get_beman_standard_config_path(): return Path(__file__).parent.parent.parent / ".beman-standard.yml" +def get_beman_recommendated_license_path(): + """ + Get the path to the Beman recommended license file. + """ + return Path(__file__).parent.parent.parent / "LICENSE" + + def load_beman_standard_config(path=get_beman_standard_config_path()): """ Load the Beman Standard YAML configuration file from the given path. diff --git a/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py b/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py index 07329da..9a39798 100644 --- a/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py +++ b/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py @@ -3,6 +3,12 @@ import re +red_color = "\033[91m" +green_color = "\033[92m" +yellow_color = "\033[93m" +gray_color = "\033[90m" +no_color = "\033[0m" + def is_snake_case(name): return re.match("(^[a-z0-9]+$)|(^[a-z0-9][a-z0-9_.]+[a-z0-9]$)", name) @@ -15,9 +21,7 @@ def is_beman_snake_case(name): """ return ( - name[:6] == "beman." - and is_snake_case(name[6:]) - and not re.match(".*[0-9]+$", name[6:]) + name[:6] != "beman." and is_snake_case(name) and not re.match(".*[0-9]+$", name) ) @@ -34,6 +38,104 @@ def match_badges(string): ] +def match_apache_license_v2_with_llvm_exceptions(content): + # beman/LICENSE contains the following text (multiple lines) + # - Apache License + # - Version 2.0 + # - LLVM Exceptions to the Apache 2.0 License + # + # We also check for variations. + # + license_regex = [ + rf"Apache License", # noqa: F541 + rf"Apache License 2\.0 with LLVM Exceptions", # noqa: F541 + rf"Apache License v2\.0 with LLVM Exceptions", # noqa: F541, + ] + if not any( + re.search(regex, content, re.IGNORECASE) is not None for regex in license_regex + ): + return False + + version_regex = [ + rf"Version 2\.0", # noqa: F541, + rf"Version v2\.0", # noqa: F541, + rf"Version 2\.0 with LLVM Exceptions", # noqa: F541, + rf"Version v2\.0 with LLVM Exceptions", # noqa: F541, + rf"Apache License 2\.0 with LLVM Exceptions", # noqa: F541 + rf"Apache License v2\.0 with LLVM Exceptions", # noqa: F541, + rf"Apache 2\.0", # noqa: F541, + rf"Apache v2\.0", # noqa: F541, + ] + if not any( + re.search(regex, content, re.IGNORECASE) is not None for regex in version_regex + ): + return False + + llvm_exceptions_regex = [ + rf"LLVM Exceptions", # noqa: F541, + rf"Apache License 2\.0 with LLVM Exceptions", # noqa: F541, + rf"Apache License v2\.0 with LLVM Exceptions", # noqa: F541, + rf"LLVM Exceptions to the Apache 2\.0 License", # noqa: F541, + ] + if not any( + re.search(regex, content, re.IGNORECASE) is not None + for regex in llvm_exceptions_regex + ): + return False + + return True + + +def match_boost_software_license_v1_0(content): + # beman/LICENSE contains the following text (multiple lines) + # - Boost Software License + # - Version 1.0 + # + # We also check for variations. + # + license_regex = [ + rf"Boost Software License", # noqa: F541 + rf"Boost License", # noqa: F541 + rf"Boost Software License 1\.0", # noqa: F541, + rf"Boost Software License Version 1\.0", # noqa: F541, + ] + if not any( + re.search(regex, content, re.IGNORECASE) is not None for regex in license_regex + ): + return False + + version_regex = [ + rf"Version 1\.0", # noqa: F541, + rf"V1\.0", # noqa: F541, + rf"Boost Software License 1\.0", # noqa: F541, + rf"Boost Software License Version 1\.0", # noqa: F541, + ] + if not any( + re.search(regex, content, re.IGNORECASE) is not None for regex in version_regex + ): + return False + + return True + + +def match_the_mit_license(content): + # beman/LICENSE contains the following text (multiple lines) + # - The MIT License + # + # We also check for variations. + # + license_regex = [ + rf"The MIT License", # noqa: F541 + rf"MIT License", # noqa: F541 + ] + if not any( + re.search(regex, content, re.IGNORECASE) is not None for regex in license_regex + ): + return False + + return True + + def skip_lines(lines, n): return lines[n:] if lines is not None else None diff --git a/infra/tools/beman-tidy/docs/dev-guide.md b/infra/tools/beman-tidy/docs/dev-guide.md index 036e473..e9739a9 100644 --- a/infra/tools/beman-tidy/docs/dev-guide.md +++ b/infra/tools/beman-tidy/docs/dev-guide.md @@ -16,27 +16,27 @@ ## Adding a new check -Find an unimplemented check in the [BEMAN_STANDARD.md](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md) file and check that is not already assigned in [Planning for beman-tidy: The Codebase Bemanification Tool](https://github.com/orgs/bemanproject/projects/8/views/1). +Find an unimplemented check in the [beman_standard.md](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md) file and check that is not already assigned in [Planning for beman-tidy: The Codebase Bemanification Tool](https://github.com/orgs/bemanproject/projects/8/views/1). -Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). +Check this PR example: [beman-tidy: add check - readme.library_status](https://github.com/bemanproject/infra/pull/35).
Step by step tutorial: add a new check -* `[mandatory]` Make sure `beman_tidy/.beman-standard.yml` reflects your check metadata (latest status from [BEMAN_STANDARD.md](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md)). +* `[mandatory]` Make sure `beman_tidy/.beman-standard.yml` reflects your check metadata (latest status from [beman_standard.md](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md)). * `[optional]` New syntax / keys from yml config can be added in [infra/tools/beman-tidy/beman_tidy/lib/utils_git.py:load_beman_standard_config()](https://github.com/bemanproject/infra/blob/main/tools/beman-tidy/beman_tidy/lib/utils/git.py) if not already implemented. Checks for TODOs in `load_beman_standard_config()`. * `[mandatory]` Add the check to the `beman_tidy/lib/checks/beman_standard/` directory. - * `[mandatory]` e.g., `README.*` checks will most likely go to a path similar to `beman_tidy/lib/checks/beman_standard/readme.py`. + * `[mandatory]` e.g., `readme.*` checks will most likely go to a path similar to `beman_tidy/lib/checks/beman_standard/readme.py`. * `[mandatory]` Use an appropriate base class - e.g., defaults like `FileBaseCheck` / `DirectoryBaseCheck` or create specializations for reusing code - e.g., `ReadmeBaseCheck(FileBaseCheck)` / `CmakeBaseCheck(FileBaseCheck)` / `CppBaseCheck(FileBaseCheck)` etc. * `[mandatory]` Register the new check via `@register_beman_standard_check` decorator - e.g., ```python - @register_beman_standard_check("README.TITLE") + @register_beman_standard_check("readme.title") class ReadmeTitleCheck(ReadmeBaseCheck): ``` @@ -71,12 +71,12 @@ rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy configfile: pyproject.toml collected 6 items -tests/beman_standard/readme/test_readme.py::test__README_TITLE__valid PASSED [ 16%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__invalid PASSED [ 33%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__fix_inplace PASSED [ 50%] -tests/beman_standard/readme/test_readme.py::test__README_BADGES__valid PASSED [ 66%] -tests/beman_standard/readme/test_readme.py::test__README_BADGES__invalid PASSED [ 83%] -tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_inplace SKIPPED (NOT implemented) [100%] +tests/beman_standard/readme/test_readme.py::test__readme_title__valid passed [ 16%] +tests/beman_standard/readme/test_readme.py::test__readme_title__invalid passed [ 33%] +tests/beman_standard/readme/test_readme.py::test__readme_title__fix_inplace passed [ 50%] +tests/beman_standard/readme/test_readme.py::test__readme_badges__valid passed [ 66%] +tests/beman_standard/readme/test_readme.py::test__readme_badges__invalid passed [ 83%] +tests/beman_standard/readme/test_readme.py::test__readme_badges__fix_inplace skipped (not implemented) [100%] =========================================================================================================== 5 passed, 1 skipped in 0.07s ============================================================================================================ ``` @@ -87,9 +87,24 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_inplace SKI check. * e.g., for `check_category = "readme"` the test file is `tests/lib/checks/beman_standard/readme/test_readme.py`. * `test____()` function inside the test file. - * e.g., for `check_category = "readme"` and `test_case_name = "valid"` the function is `test__README_TITLE__valid()`. - * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the function is - `test__README_TITLE__invalid()`. + * `test_case_name` can be `valid`, `invalid`, `fix_inplace` or `skipped`. + * If the check is implemented and must be run, add 3 test functions: `valid`, `invalid` and `fix_inplace` (some of them can be a `@pytest.mark.skip(reason="not implemented")` decorator, but at least one must be actually implemented). + * If the check is implemented as a dummy (e.g., cannot be properly implemented), add the `skipped` function. + `should_skip()` must log a reason why it is skipped. + * Note: The number of tests is already enforced by a unit test in `tests/lib/checks/system/test_registry.py`, which is looking for the test functions for new added checks! + * Examples: + * Runnable check - `readme.title`: + * for `check_category = "readme"` and `test_case_name = "valid"` the function is `test__readme_title__valid()`. + * for `check_category = "readme"` and `test_case_name = "invalid"` the function is + `test__readme_title__invalid()`. + * for `check_category = "readme"` and `test_case_name = "fix_inplace"` the function is + `test__readme_title__fix_inplace()`. + * Skippable check - `license.criteria`: + * for `check_category = "license"` and `test_case_name = "skipped"` the function is + `test__license_criteria__skipped()`. + * `should_skip()` must log a reason why it is skipped. + * `should_skip()` must return `True`. + * `check()` and `fix()` must provide a `return True` implementation. * `tests/beman_standard//data/`: The data for the tests (e.g., files, directories, etc.). * e.g., for `check_category = "readme"` and `test_case_name = "valid"` the data is in `tests/lib/checks/beman_standard/readme/data/valid/`. @@ -106,7 +121,7 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_inplace SKI * `valid`: The test case for the valid case. * `invalid`: The test case for the invalid case. * `fix_inplace`: The test case for the fix invalid case. If the fix is not (yet) implementable, add a - `@pytest.mark.skip(reason="NOT implemented")` decorator to track the progress. + `@pytest.mark.skip(reason="not implemented")` decorator to track the progress. ## Changing dependencies @@ -127,6 +142,7 @@ Requirements: * `beman-tidy` must have `verbose` and `non-verbose` modes. Default is `non-verbose`. * `beman-tidy` must have `dry-run` and `fix-inplace` modes. Default is `dry-run`. * `beman-tidy` must detect types of checks: failed, passed, skipped (not implemented) and print the summary/coverage. +* `beman-tidy` can access configuration files shipped with the tool itself (e.g., `.beman-standard.yml` or `LICENSE`). All such files must be in the `beman_tidy/` directory to be automatically available in exported packages. It cannot access files from the repository itself (e.g., `infra/LICENSE` or `infra/tools/beman-tidy/README.md`). Limitations: diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py new file mode 100644 index 0000000..515dc2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/abstract.bst b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/abstract.bst new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/abstract.bst @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/dummy.tex b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/dummy.tex new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/dummy.tex @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/src/beman/optional/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/src/beman/optional/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/src/beman/optional/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/abstract.bst b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/abstract.bst new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/abstract.bst @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/dummy.tex b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/dummy.tex new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/P2988/dummy.tex @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/debug/ci.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/debug/ci.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/debug/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/examples/.keep b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/examples/.keep new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/src/beman/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/src/beman/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/src/beman/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/tests/beman/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/tests/beman/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/tests/beman/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/dev/lint.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/dev/lint.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/dev/lint.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/examples/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/examples/CMakeLists.txt new file mode 100644 index 0000000..09bc784 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/examples/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/src/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/src/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/src/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/tests/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/tests/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/tests/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/deps/dummy.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/deps/dummy.txt new file mode 100644 index 0000000..a37fa5a --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/deps/dummy.txt @@ -0,0 +1 @@ +# Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/generated/dummy.pdf b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/generated/dummy.pdf new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/img/note.png b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/img/note.png new file mode 100644 index 0000000..e24b382 Binary files /dev/null and b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/wg21/img/note.png differ diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/debug/ci.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/debug/ci.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/debug/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/dev/lint.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/dev/lint.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/dev/lint.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/local.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/local.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/local.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/optional.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/optional.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/optional.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/examples/dummy.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/examples/dummy.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/examples/dummy.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/abstract.bst b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/abstract.bst new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/abstract.bst @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/dummy.tex b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/dummy.tex new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/reports/P2988/dummy.tex @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/sources/beman/exemplar/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/sources/beman/exemplar/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/sources/beman/exemplar/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/tests/beman/exemplar/.keep b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/tests/beman/exemplar/.keep new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/examples/example.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/examples/example.txt new file mode 100644 index 0000000..f3ae800 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/examples/example.txt @@ -0,0 +1 @@ +Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/source/beman/exemplar/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/source/beman/exemplar/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/source/beman/exemplar/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/test_types.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/test_types.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/test_types.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/test_types.hpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/test_types.hpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/test_types.hpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/tests/beman/exemplar/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/tests/beman/exemplar/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/tests/beman/exemplar/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/lib/beman/exemplar/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/lib/beman/exemplar/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/lib/beman/exemplar/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/tests/beman/exemplar/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/tests/beman/exemplar/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/tests/beman/exemplar/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/library/beman/exemplar/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/library/beman/exemplar/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/library/beman/exemplar/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/testing/beman/exemplar/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/testing/beman/exemplar/CMakeLists.txt new file mode 100644 index 0000000..09bc784 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/testing/beman/exemplar/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/testing/beman/exemplar/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/testing/beman/exemplar/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/testing/beman/exemplar/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/examples/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/examples/CMakeLists.txt new file mode 100644 index 0000000..09bc784 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/examples/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/examples/dummy.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/examples/dummy.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/examples/dummy.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/src/beman/exemplar/exemplar.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/src/beman/exemplar/exemplar.cpp new file mode 100644 index 0000000..fe82757 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/src/beman/exemplar/exemplar.cpp @@ -0,0 +1 @@ +// Dummy content, this file is used only for testing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/CMakeLists.txt new file mode 100644 index 0000000..09bc784 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/identity.test.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/identity.test.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/identity.test.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_types.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_types.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_types.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_types.hpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_types.hpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_types.hpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_utilities.cpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_utilities.cpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_utilities.cpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_utilities.hpp b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_utilities.hpp new file mode 100644 index 0000000..4c20f85 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/tests/beman/exemplar/test_utilities.hpp @@ -0,0 +1 @@ +// Dummy content diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/.keep b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/.keep new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/debug/ci.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/debug/ci.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/debug/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/dev/lint.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/dev/lint.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/dev/lint.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/local.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/local.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/local.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/optional.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/optional.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/optional.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/README.md new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/abstract.bst b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/abstract.bst new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/abstract.bst @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/dummy.tex b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/dummy.tex new file mode 100644 index 0000000..2acefc8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/dummy.tex @@ -0,0 +1 @@ +Dummy content. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py new file mode 100644 index 0000000..bc8c60c --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest +from pathlib import Path + +from tests.utils.path_runners import ( + run_check_for_each_path, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.directory import ( + DirectoryDocsCheck, + DirectoryExamplesCheck, + DirectoryPapersCheck, + DirectorySourcesCheck, + DirectoryTestsCheck, +) + +test_data_prefix = "tests/lib/checks/beman_standard/directory/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" + + +def test__directory_sources__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid CMakeLists.txt. + """ + valid_cmake_paths = [ + # exemplar/ repo with src/beman/exemplar/ - valid source tree. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo without src/ - no source files (header-only). + Path(f"{valid_prefix}/repo-exemplar-v2/"), + ] + + run_check_for_each_path( + True, + valid_cmake_paths, + DirectorySourcesCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__directory_sources__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid CMakeLists.txt. + """ + invalid_cmake_paths = [ + # Sources in src/beman/optional - wrong inner directory. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Sources in src/beman/ - missing 3rd subdirectory. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # Sources in src/ - missing 2nd and 3rd subdirectories. + Path(f"{invalid_prefix}/repo-exemplar-v3"), + # Sources in sources/ - wrong prefix. + Path(f"{invalid_prefix}/repo-exemplar-v4"), + # Sources in source/ - wrong prefix. + Path(f"{invalid_prefix}/repo-exemplar-v5"), + # Sources in lib/ - wrong prefix. + Path(f"{invalid_prefix}/repo-exemplar-v6"), + # Sources in library/ - wrong prefix. + Path(f"{invalid_prefix}/repo-exemplar-v7"), + ] + + run_check_for_each_path( + False, + invalid_cmake_paths, + DirectorySourcesCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__directory_sources__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid sources directory structure. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__directory_tests__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with test files within the top-level tests/ directory pass the check. + """ + valid_tests_paths = [ + # exemplar/ repo with correct tests/ dir and a relevant example. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_tests_paths, + DirectoryTestsCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__directory_tests__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with test files outside the top-level tests/ directory fail the check. + """ + invalid_tests_paths = [ + # exemplar/ repo without tests/beman/ dir. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Tests in tests/beman - Missing 3rd subdirectory. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # Tests in tests/ - Missing 2nd and 3rd subdirectories. + Path(f"{invalid_prefix}/repo-exemplar-v3"), + # Empty tests/beman/ dir. + Path(f"{invalid_prefix}/repo-exemplar-v4"), + # Test files outside tests/beman/ dir. + Path(f"{invalid_prefix}/repo-exemplar-v5"), + # Missing relevant example in tests/beman/ dir. + Path(f"{invalid_prefix}/repo-exemplar-v6"), + # Wrong name for tests/ directory. + Path(f"{invalid_prefix}/repo-exemplar-v7"), + ] + + run_check_for_each_path( + False, + invalid_tests_paths, + DirectoryTestsCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__directory_tests__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid test directory structure. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__directory_examples__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid examples directory pass the check. + """ + valid_examples_paths = [ + # exemplar/ repo with correct examples/ dir. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_examples_paths, + DirectoryExamplesCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__directory_examples__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid examples directory fail the check. + """ + invalid_examples_paths = [ + # Missing examples/ directory. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Empty examples/ directory. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # examples/ directory without .cpp files. + Path(f"{invalid_prefix}/repo-exemplar-v3"), + # examples/ directory without CMakeLists.txt files. + Path(f"{invalid_prefix}/repo-exemplar-v4"), + # examples/ directory with no relevant example files. + Path(f"{invalid_prefix}/repo-exemplar-v5"), + ] + + run_check_for_each_path( + False, + invalid_examples_paths, + DirectoryExamplesCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__directory_examples__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid examples directory structure. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__directory_docs__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid documentation structure pass the check. + """ + valid_docs_paths = [ + # exemplar/ repo without docs/ dir and with root README.md. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with docs/ dir and root README.md. + Path(f"{valid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo with papers/ dir and root README.md. + Path(f"{valid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + True, + valid_docs_paths, + DirectoryDocsCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__directory_docs__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid documentation structure fail the check. + """ + invalid_docs_paths = [ + # Misplaced MD files in root directory. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Misplaced MD files in root subdirectories. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # Misplaced MD files in root directory and root subdirectories. + Path(f"{invalid_prefix}/repo-exemplar-v3"), + # Wrong name for docs/ directory. + Path(f"{invalid_prefix}/repo-exemplar-v4"), + ] + + run_check_for_each_path( + False, + invalid_docs_paths, + DirectoryDocsCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__directory_docs__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid documentation structure. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__directory_papers__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid paper structure pass the check. + """ + valid_papers_paths = [ + # exemplar/ repo without papers/ dir. + Path(f"{valid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo with papers/ dir. + Path(f"{valid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + True, + valid_papers_paths, + DirectoryPapersCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__directory_papers__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid paper structure fail the check. + """ + invalid_papers_paths = [ + # Misplaced paper-related files in root directory. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Misplaced P2988 directory. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # Misplaced wg21 directory. + Path(f"{invalid_prefix}/repo-exemplar-v3"), + # Wrong name for papers/ directory. + Path(f"{invalid_prefix}/repo-exemplar-v4"), + ] + + run_check_for_each_path( + False, + invalid_papers_paths, + DirectoryPapersCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__directory_papers__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid paper structure. + Note: Skipping this test as it is not implemented. + """ + pass diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py new file mode 100644 index 0000000..515dc2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/.keep b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/.keep new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py new file mode 100644 index 0000000..6b59edd --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.general import ( + LibraryNameCheck, +) + + +def test__library_name__is_always_skipped(repo_info, beman_standard_check_config): + """ + Test that library.name is always skipped, as it cannot be implemented. + """ + assert LibraryNameCheck(repo_info, beman_standard_check_config).should_skip() diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/conftest.py new file mode 100644 index 0000000..515dc2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 new file mode 100644 index 0000000..f6db814 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 @@ -0,0 +1,219 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 new file mode 100644 index 0000000..604004a --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2025 The Beman Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py new file mode 100644 index 0000000..a6d0fe8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest +from pathlib import Path + +from tests.utils.path_runners import ( + run_check_for_each_path, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.license import ( + LicenseApprovedCheck, + LicenseApacheLLVMCheck, + LicenseCriteriaCheck, +) + +test_data_prefix = "tests/lib/checks/beman_standard/license/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" + + +def test__license_approved__valid(repo_info, beman_standard_check_config): + """ + Test that a valid LICENSE file passes the check. + """ + valid_license_paths = [ + # Apache License v2.0 with LLVM Exceptions + Path(f"{valid_prefix}/valid-LICENSE-v1"), + # Boost Software License - Version 1.0 + Path(f"{valid_prefix}/valid-LICENSE-v2"), + # The MIT License + Path(f"{valid_prefix}/valid-LICENSE-v3"), + ] + + run_check_for_each_path( + True, + valid_license_paths, + LicenseApprovedCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__license_approved__invalid(repo_info, beman_standard_check_config): + """ + Test that an invalid LICENSE file fails the check. + """ + invalid_license_paths = [ + # TODO + ] + + run_check_for_each_path( + False, + invalid_license_paths, + LicenseApprovedCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__license_approved__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid LICENSE file. + """ + # Cannot determine what license to create. fix() is not implemented. + pass + + +def test__license_apache_llvm__valid(repo_info, beman_standard_check_config): + """ + Test that a LICENSE file with Apache LLVM passes the check. + """ + valid_license_paths = [ + # Apache License v2.0 with LLVM Exceptions is the only one compatible with license.apache_llvm. + Path(f"{valid_prefix}/valid-LICENSE-v1"), + ] + + run_check_for_each_path( + True, + valid_license_paths, + LicenseApacheLLVMCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__license_apache_llvm__invalid(repo_info, beman_standard_check_config): + """ + Test that a LICENSE file without Apache LLVM fails the check. + """ + invalid_license_paths = [ + # Boost Software License 1.0 is license.approved compatible, but not compatible with license.apache_llvm. + Path(f"{valid_prefix}/valid-LICENSE-v2"), + # MIT License is license.approved compatible, but not compatible with license.apache_llvm. + Path(f"{valid_prefix}/valid-LICENSE-v3"), + ] + + run_check_for_each_path( + False, + invalid_license_paths, + LicenseApacheLLVMCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__license_apache_llvm__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid LICENSE file. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__license_criteria__is_always_skipped(repo_info, beman_standard_check_config): + """ + Test that license.criteria is always skipped, as it cannot be implemented. + """ + assert LicenseCriteriaCheck(repo_info, beman_standard_check_config).should_skip() diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md index 5be8ed8..507789d 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md @@ -3,14 +3,13 @@ -![Library typo Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![Library typo 1 Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) -This is NOT a valid README.md according to the Beman Standard: typos in badges. +This is NOT a valid README.md according to the Beman Standard: typos in badge for library status. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md index 4aa668e..5b33888 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md @@ -3,13 +3,13 @@ -![Other display text](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard typo 2 Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) -This is NOT a valid README.md according to the Beman Standard: invalid badge display text. +This is NOT a valid README.md according to the Beman Standard: typos in badge for standard target. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md index ffc08c3..8398757 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md @@ -3,13 +3,13 @@ -![Library Status](https://raw.githubusercontent.com/mylogo) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![other description 1](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) -This is NOT a valid README.md according to the Beman Standard: invalid badge URL. +This is NOT a valid README.md according to the Beman Standard: other description in badge for library status. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v4.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v4.md new file mode 100644 index 0000000..9534abe --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v4.md @@ -0,0 +1,15 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![other description 2](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +This is NOT a valid README.md according to the Beman Standard: other description in badge for standard target. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v5.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v5.md new file mode 100644 index 0000000..489603a --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v5.md @@ -0,0 +1,15 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_non-sense.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +This is NOT a valid README.md according to the Beman Standard: non-sense badge for library status (broken badge URL). diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v6.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v6.md new file mode 100644 index 0000000..46c8c8a --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v6.md @@ -0,0 +1,15 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp-non-sense.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +This is NOT a valid README.md according to the Beman Standard: non-sense badge for standard target (broken badge URL). diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v7.md similarity index 74% rename from infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md rename to infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v7.md index eea29e4..6ce5841 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v7.md @@ -1,4 +1,4 @@ -# beman.optional: C++26 Optional Library +# beman.exemplar: A Beman Library Exemplar @@ -6,10 +6,10 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) -This is NOT a valid README.md according to the Beman Standard: wrong library name. +This is NOT a valid README.md according to the Beman Standard: 1/2 badges are missing (standard target). diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v8.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v8.md new file mode 100644 index 0000000..7d7f064 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v8.md @@ -0,0 +1,15 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +This is NOT a valid README.md according to the Beman Standard: 1/2 badges are missing (library status). diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md new file mode 100644 index 0000000..037b574 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md @@ -0,0 +1,19 @@ +# beman.exemplar: A Beman Library Exemplar + + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) + + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + + + +This is NOT a valid README.md according to the Beman Standard: missing P number in the implements section. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md new file mode 100644 index 0000000..3fd28f3 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md @@ -0,0 +1,19 @@ +# beman.exemplar: A Beman Library Exemplar + + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) + + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)]. + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + + + +This is NOT a valid README.md according to the Beman Standard: missing wg url in the implements section. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md new file mode 100644 index 0000000..6ef40c3 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md @@ -0,0 +1,19 @@ +# beman.exemplar: A Beman Library Exemplar + + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) + + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +Implements: `std::identity` proposed in [Standard Library Concepts](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + + + +This is NOT a valid README.md according to the Beman Standard: missing bold for Implements. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md new file mode 100644 index 0000000..5e9228b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md @@ -0,0 +1,22 @@ +# beman.exemplar: A Beman Library Exemplar + + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) + + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Implements**: [Give _std::optional_ Range Support (P3168R2)](https://wg21.link/P3168R2) and [`std::optional` (P2988R5)](https://wg21.link/P2988R5) + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + + + + +This is NOT a valid README.md according to the Beman Standard: duplicate implements line. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v1.md new file mode 100644 index 0000000..71a33fa --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v1.md @@ -0,0 +1,17 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +This project is licensed under the Apache License 2.0 with LLVM Exceptions. + +This is NOT a valid README.md according to the Beman Standard: missing license section. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v2.md new file mode 100644 index 0000000..ffc40b3 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v2.md @@ -0,0 +1,17 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +## License + +This is NOT a valid README.md according to the Beman Standard: empty license section. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v3.md new file mode 100644 index 0000000..b6479e6 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-license-section-v3.md @@ -0,0 +1,21 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +## License + +This is license under the Blah Blah license. + +## Other + +This is NOT a valid README.md according to the Beman Standard: valid section, but invalid license. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md index bdef579..03a83d1 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md @@ -6,7 +6,7 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md index a4da50f..c24f596 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md @@ -6,11 +6,11 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md# TYPO HERE under-development-and-not-yet-ready-for-production-use) +**Status**: [under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md# TYPO HERE under-development-and-not-yet-ready-for-production-use) This is NOT a valid README.md according to the Beman Standard: the library status line has typos. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md index 8d5e2bd..bb54ec1 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md @@ -6,13 +6,13 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use), -**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-api-may-undergo-changes), -**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-stable-api), -**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#retired-no-longer-maintained-or-actively-developed), +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use), +**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-api-may-undergo-changes), +**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-stable-api), +**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#retired-no-longer-maintained-or-actively-developed), This is NOT a valid README.md according to the Beman Standard: the library status is duplicated. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md index 7f91a7a..c13f906 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md @@ -6,10 +6,10 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) This is NOT a valid README.md according to the Beman Standard: missing beman.exemplar. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md index e92b46f..3353fbe 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md @@ -6,10 +6,10 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) This is NOT a valid README.md according to the Beman Standard: missing : diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md index 6ae059f..d9b7afb 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md @@ -6,11 +6,11 @@ ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) This is NOT a valid README.md according to the Beman Standard: wrong library name. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md index 403859d..4bf45d0 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md @@ -3,14 +3,20 @@ -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + +## License + +This project is licensed under the Apache License 2.0 with LLVM Exceptions. + +## Other This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. @@ -24,3 +30,5 @@ This is a valid README.md file that follows the Beman Standard: the implements i This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. This is a valid README.md file that follows the Beman Standard: the license is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the license is properly formatted - Apache License 2.0 with LLVM Exceptions. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md index 56e5a72..a89295d 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md @@ -3,14 +3,20 @@ -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_production_ready_api_may_undergo_changes.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp29.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-api-may-undergo-changes) +**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-api-may-undergo-changes) + +## License + +This project is licensed under the Boost Software License 1.0. + +## Other This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. @@ -24,3 +30,5 @@ This is a valid README.md file that follows the Beman Standard: the implements i This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. This is a valid README.md file that follows the Beman Standard: the license is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the license is properly formatted - Boost Software License 1.0. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md index dbfbace..e160bc3 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md @@ -3,15 +3,25 @@ -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_production_ready_stable_api.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp29.svg) -beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-stable-api) +**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#production-ready-stable-api) + +## License + +This project is licensed under the MIT License. + +## Other + +This is a valid README.md file that follows the Beman Standard: the license is properly formatted - MIT License. + +## Other This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. @@ -24,4 +34,4 @@ This is a valid README.md file that follows the Beman Standard: the implements i This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. -This is a valid README.md file that follows the Beman Standard: the license is properly formatted. +This is a valid README.md file that follows the Beman Standard: the license is properly formatted - MIT License. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md index c33c603..60809f7 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md @@ -3,14 +3,20 @@ -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_retired.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). -**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#retired-no-longer-maintained-or-actively-developed) +**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#retired-no-longer-maintained-or-actively-developed) + +## License + +This project is licensed under the Apache License 2.0 with LLVM Exceptions blah blah, and for tooling, the docs are under the MIT License. + +## Other This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. @@ -23,4 +29,4 @@ This is a valid README.md file that follows the Beman Standard: the implements i This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. -This is a valid README.md file that follows the Beman Standard: the license is properly formatted. +This is a valid README.md file that follows the Beman Standard: the license is properly formatted - contains multiple valid licenses. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 476a180..d9ea270 100644 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -11,9 +11,12 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.readme import ( + ReadmePurposeCheck, ReadmeTitleCheck, ReadmeBadgesCheck, + ReadmeImplementsCheck, ReadmeLibraryStatusCheck, + ReadmeLicenseCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/readme/data" @@ -21,7 +24,14 @@ invalid_prefix = f"{test_data_prefix}/invalid" -def test__README_TITLE__valid(repo_info, beman_standard_check_config): +def test__readme_purpose__is_always_skipped(repo_info, beman_standard_check_config): + """ + Test that readme.purpose is always skipped, as it cannot be implemented. + """ + assert ReadmePurposeCheck(repo_info, beman_standard_check_config).should_skip() + + +def test__readme_title__valid(repo_info, beman_standard_check_config): """ Test that a valid README.md title passes the check. """ @@ -45,16 +55,19 @@ def test__README_TITLE__valid(repo_info, beman_standard_check_config): ) -def test__README_TITLE__invalid(repo_info, beman_standard_check_config): +def test__readme_title__invalid(repo_info, beman_standard_check_config): """ Test that an invalid README.md title fails the check. """ invalid_readme_paths = [ + # Title: Wrong Title Format Path(f"{invalid_prefix}/invalid.md"), + # Title: Missing . in beman.exemplar Path(f"{invalid_prefix}/invalid-title-v1.md"), + # Title: Missing : after beman.exemplar Path(f"{invalid_prefix}/invalid-title-v2.md"), + # Title: Wromg name beman.exemaplar vs beman.optional Path(f"{invalid_prefix}/invalid-title-v3.md"), - Path(f"{invalid_prefix}/invalid-title-v4.md"), ] run_check_for_each_path( @@ -66,7 +79,7 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): ) -def test__README_TITLE__fix_inplace(repo_info, beman_standard_check_config): +def test__readme_title__fix_inplace(repo_info, beman_standard_check_config): """ Test that the fix method corrects an invalid README.md title. """ @@ -74,7 +87,6 @@ def test__README_TITLE__fix_inplace(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-title-v1.md"), Path(f"{invalid_prefix}/invalid-title-v2.md"), Path(f"{invalid_prefix}/invalid-title-v3.md"), - Path(f"{invalid_prefix}/invalid-title-v4.md"), ] run_fix_inplace_for_each_file_path( @@ -82,14 +94,18 @@ def test__README_TITLE__fix_inplace(repo_info, beman_standard_check_config): ) -def test__README_BADGES__valid(repo_info, beman_standard_check_config): +def test__readme_badges__valid(repo_info, beman_standard_check_config): """ Test that a valid README.md badges passes the check. """ valid_readme_paths = [ + # Badges: under development status and cpp26 target Path(f"{valid_prefix}/README-v1.md"), + # Badges: production ready (api may undergo changes) status and cpp26 target Path(f"{valid_prefix}/README-v2.md"), + # Badges: production ready (stable api) status and cpp29 target Path(f"{valid_prefix}/README-v3.md"), + # Badges: retired status and cpp26 target Path(f"{valid_prefix}/README-v4.md"), ] @@ -102,15 +118,28 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config): ) -def test__README_BADGES__invalid(repo_info, beman_standard_check_config): +def test__readme_badges__invalid(repo_info, beman_standard_check_config): """ Test that an invalid README.md badges fails the check. """ invalid_readme_paths = [ Path(f"{invalid_prefix}/invalid.md"), + # Badges: typos in badge for library status Path(f"{invalid_prefix}/invalid-badge-v1.md"), + # Badges: typos in badge for standard target Path(f"{invalid_prefix}/invalid-badge-v2.md"), + # Badges: other description in badge for library status Path(f"{invalid_prefix}/invalid-badge-v3.md"), + # Badges: other description in badge for standard target + Path(f"{invalid_prefix}/invalid-badge-v4.md"), + # Badges: non-sense badge for library status (broken badge URL) + Path(f"{invalid_prefix}/invalid-badge-v5.md"), + # Badges: non-sense badge for standard target (broken badge URL) + Path(f"{invalid_prefix}/invalid-badge-v6.md"), + # Badges: 1/2 badges are missing (standard target) + Path(f"{invalid_prefix}/invalid-badge-v7.md"), + # Badges: 1/2 badges are missing (library status) + Path(f"{invalid_prefix}/invalid-badge-v8.md"), ] run_check_for_each_path( @@ -122,15 +151,66 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): ) -@pytest.mark.skip(reason="NOT implemented") -def test__README_BADGES__fix_inplace(repo_info, beman_standard_check_config): +@pytest.mark.skip(reason="not implemented") +def test__readme_badges__fix_inplace(repo_info, beman_standard_check_config): """ Test that the fix method corrects an invalid README.md badges. + Note: Skipping this test as it is not implemented. """ pass -def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): +def test__readme_implements__valid(repo_info, beman_standard_check_config): + """ + Test that a valid README.md "Implements" passes the check + """ + valid_readme_paths = [ + Path(f"{valid_prefix}/README-v1.md"), + Path(f"{valid_prefix}/README-v2.md"), + Path(f"{valid_prefix}/README-v3.md"), + Path(f"{valid_prefix}/README-v4.md"), + ] + + run_check_for_each_path( + True, + valid_readme_paths, + ReadmeImplementsCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__readme_implements__invalid(repo_info, beman_standard_check_config): + """ + Test that an invalid README.md "Implements" fails the check + """ + invalid_readme_paths = [ + Path(f"{invalid_prefix}/invalid.md"), + Path(f"{invalid_prefix}/invalid-implements-v1.md"), + Path(f"{invalid_prefix}/invalid-implements-v2.md"), + Path(f"{invalid_prefix}/invalid-implements-v3.md"), + Path(f"{invalid_prefix}/invalid-implements-v4.md"), + ] + + run_check_for_each_path( + False, + invalid_readme_paths, + ReadmeImplementsCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__readme_implements__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid README.md "Implements". + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__readme_library_status__valid(repo_info, beman_standard_check_config): """ Test that a valid README.md library status passes the check. """ @@ -150,7 +230,7 @@ def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): ) -def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config): +def test__readme_library_status__invalid(repo_info, beman_standard_check_config): """ Test that an invalid README.md library status fails the check. """ @@ -170,9 +250,65 @@ def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config) ) -@pytest.mark.skip(reason="NOT implemented") -def test__README_LIBRARY_STATUS__fix_inplace(repo_info, beman_standard_check_config): +@pytest.mark.skip(reason="not implemented") +def test__readme_library_status__fix_inplace(repo_info, beman_standard_check_config): """ Test that the fix method corrects an invalid README.md library status. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__readme_license__valid(repo_info, beman_standard_check_config): + """ + Test that a valid README.md license passes the check. + """ + valid_readme_paths = [ + # License: Apache License 2.0 with LLVM Exceptions + Path(f"{valid_prefix}/README-v1.md"), + # License: Boost Software License 1.0 + Path(f"{valid_prefix}/README-v2.md"), + # License: MIT License + Path(f"{valid_prefix}/README-v3.md"), + # License: Apache License 2.0 with LLVM Exceptions and MIT License + Path(f"{valid_prefix}/README-v4.md"), + ] + + run_check_for_each_path( + True, + valid_readme_paths, + ReadmeLicenseCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__readme_license__invalid(repo_info, beman_standard_check_config): + """ + Test that an invalid README.md license fails the check. + """ + invalid_readme_paths = [ + # License: Missing license section + Path(f"{invalid_prefix}/invalid-license-section-v1.md"), + # License: Empty license section + Path(f"{invalid_prefix}/invalid-license-section-v2.md"), + # License: Invalid license + Path(f"{invalid_prefix}/invalid-license-section-v3.md"), + ] + + run_check_for_each_path( + False, + invalid_readme_paths, + ReadmeLicenseCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__readme_license__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid README.md license. + Note: Skipping this test as it is not implemented. """ pass diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/conftest.py new file mode 100644 index 0000000..515dc2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/invalid/repo-exemplar-v1/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/invalid/repo-exemplar-v1/README.md new file mode 100644 index 0000000..39a23a8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/invalid/repo-exemplar-v1/README.md @@ -0,0 +1,28 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + + +This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. + +This is a valid README.md file that follows the Beman Standard: the badges are properly formatted. + +This is a valid README.md file that follows the Beman Standard: the purpose is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the implements is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the license is properly formatted. + +This is an invalid README.md file that follows the Beman Standard: the Godbolt badge is missing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/valid/repo-exemplar-v1/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/valid/repo-exemplar-v1/README.md new file mode 100644 index 0000000..8135dfc --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/valid/repo-exemplar-v1/README.md @@ -0,0 +1,28 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) ![Standard Target](https://github.com/bemanproject/beman/blob/main/images/badges/cpp26.svg) [![Compiler Explorer Example](https://img.shields.io/badge/Try%20it%20on%20Compiler%20Explorer-grey?logo=compilerexplorer&logoColor=67c52a)](https://godbolt.org/z/Gc6Y9j6zf) + + +`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. + +**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + +**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) + + +This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. + +This is a valid README.md file that follows the Beman Standard: the badges are properly formatted. + +This is a valid README.md file that follows the Beman Standard: the purpose is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the implements is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the license is properly formatted. + +This is a valid README.md file that follows the Beman Standard: the Godbolt badge is present. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py new file mode 100644 index 0000000..ab2d9fc --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest +from pathlib import Path + +from tests.utils.path_runners import ( + run_check_for_each_path, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.release import ( + ReleaseGithubCheck, + ReleaseGodboltTrunkVersionCheck, + ReleaseNotesCheck, +) + +test_data_prefix = "tests/lib/checks/beman_standard/release/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" + + +def test__release_github__is_always_skipped(repo_info, beman_standard_check_config): + """ + Test that release.github is always skipped, as it cannot be implemented. + """ + assert ReleaseGithubCheck(repo_info, beman_standard_check_config).should_skip() + + +def test__release_notes__is_always_skipped(repo_info, beman_standard_check_config): + """ + Test that release.notes is always skipped, as it cannot be implemented. + """ + assert ReleaseNotesCheck(repo_info, beman_standard_check_config).should_skip() + + +def test__release_godbolt_trunk_version__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with present Godbolt trunk version pass the check. + """ + valid_godbolt_trunk_version_paths = [ + # exemplar/ repo with root README.md containing valid Godbolt trunk version. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_godbolt_trunk_version_paths, + ReleaseGodboltTrunkVersionCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__release_godbolt_trunk_version__invalid( + repo_info, beman_standard_check_config +): + """ + Test that repositories with missing Godbolt trunk version fail the check. + """ + invalid_godbolt_trunk_version_paths = [ + # exemplar/ repo root README.md without Godbolt trunk version. + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + False, + invalid_godbolt_trunk_version_paths, + ReleaseGodboltTrunkVersionCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__release_godbolt_trunk_version__fix_inplace( + repo_info, beman_standard_check_config +): + """ + Test that the fix method corrects an invalid README.md Godbolt trunk version. + Note: Skipping this test as it is not implemented. + """ + pass diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/conftest.py new file mode 100644 index 0000000..515dc2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.github/.keep b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.github/.keep new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules new file mode 100644 index 0000000..d438b89 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules @@ -0,0 +1,3 @@ +[submodule "dummy"] + path = dummy + url = https://github.com/cplusplus/dummy diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules new file mode 100644 index 0000000..cb06c9e --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules @@ -0,0 +1,9 @@ +[submodule "dummy1"] + path = dummy1 + url = https://github.com/dummy1.git +[submodule "wg21"] + path = wg21 + url = https://github.com/mpark/wg21.git +[submodule "dummy2"] + path = dummy2 + url = https://github.com/cplusplus/dummy2 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/CODEOWNERS b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/CODEOWNERS new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules new file mode 100644 index 0000000..50ecb2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules @@ -0,0 +1,6 @@ +[submodule "dummy1"] + path = dummy1 + url = https://github.com/dummy1.git +[submodule "dummy2"] + path = dummy2 + url = https://github.com/cplusplus/dummy2 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v1/.github/CODEOWNERS b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v1/.github/CODEOWNERS new file mode 100644 index 0000000..dcd78f5 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v1/.github/CODEOWNERS @@ -0,0 +1 @@ +* @neatudarius diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules new file mode 100644 index 0000000..3211848 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules @@ -0,0 +1,3 @@ +[submodule "wg21"] + path = papers/wg21 + url = https://github.com/mpark/wg21.git diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v3/.gitmodules b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v3/.gitmodules new file mode 100644 index 0000000..b44d8c0 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v3/.gitmodules @@ -0,0 +1,3 @@ +[submodule "papers/wg21"] + path = papers/P2988/wg21 + url = https://github.com/mpark/wg21.git diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py new file mode 100644 index 0000000..63ab1aa --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest +from pathlib import Path + +from tests.utils.path_runners import ( + run_check_for_each_path, + run_check_for_each_repo_info, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.repository import ( + RepositoryNameCheck, + RepositoryDefaultBranchCheck, + RepositoryCodeownersCheck, + RepositoryCodeReviewRulesCheck, + RepositoryDisallowGitSubmodulesCheck, +) + +test_data_prefix = "tests/lib/checks/beman_standard/repository/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" + + +def test__repository_name__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid repository names pass the check. + """ + # Create mock repo info with valid repository names + valid_repo_infos = [ + repo_info.copy() | {"name": "exemplar"}, + repo_info.copy() | {"name": "optional"}, + repo_info.copy() | {"name": "smart_pointer"}, + repo_info.copy() | {"name": "execution"}, + repo_info.copy() | {"name": "utf_view"}, + repo_info.copy() | {"name": "net"}, + ] + + run_check_for_each_repo_info( + True, + RepositoryNameCheck, + valid_repo_infos, + beman_standard_check_config, + ) + + +def test__repository_name__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid repository names fail the check. + """ + # Create mock repo info with invalid repository names + invalid_repo_infos = [ + repo_info.copy() | {"name": "beman.exemplar"}, + repo_info.copy() | {"name": "exemplar26"}, + repo_info.copy() | {"name": "beman.exemplar26"}, + repo_info.copy() | {"name": "exemplar_"}, + repo_info.copy() | {"name": "_exemplar"}, + repo_info.copy() | {"name": "optional26"}, + repo_info.copy() | {"name": "execution26"}, + repo_info.copy() | {"name": "net29"}, + ] + + run_check_for_each_repo_info( + False, + RepositoryNameCheck, + invalid_repo_infos, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__repository_name__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid repository name. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__repository_default_branch__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid default branch pass the check. + """ + # Create mock repo info with valid default branch + valid_repo_infos = [ + repo_info.copy() | {"default_branch": "main"}, + ] + + run_check_for_each_repo_info( + True, + RepositoryDefaultBranchCheck, + valid_repo_infos, + beman_standard_check_config, + ) + + +def test__repository_default_branch__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid default branch fail the check. + """ + # Test various invalid branch names + invalid_repo_infos = [ + repo_info.copy() | {"default_branch": "master"}, + repo_info.copy() | {"default_branch": "develop"}, + repo_info.copy() | {"default_branch": "dev"}, + repo_info.copy() | {"default_branch": "trunk"}, + repo_info.copy() | {"default_branch": "default"}, + repo_info.copy() | {"default_branch": "production"}, + repo_info.copy() | {"default_branch": "release"}, + repo_info.copy() | {"default_branch": "stable"}, + repo_info.copy() | {"default_branch": "testing"}, + repo_info.copy() | {"default_branch": "alpha"}, + repo_info.copy() | {"default_branch": "beta"}, + repo_info.copy() | {"default_branch": "experimental"}, + ] + + run_check_for_each_repo_info( + False, + RepositoryDefaultBranchCheck, + invalid_repo_infos, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__repository_default_branch__fix_inplace( + repo_info, beman_standard_check_config +): + """ + Test that the fix method corrects an invalid default branch. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__repository_codeowners__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid CODEOWNERS pass the check. + """ + valid_codeowners_paths = [ + # exemplar/ repo with valid .github/CODEOWNERS file. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_codeowners_paths, + RepositoryCodeownersCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__repository_codeowners__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid CODEOWNERS fail the check. + """ + invalid_codeowners_paths = [ + # exemplar/ repo without CODEOWNERS file inside .github/. + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with CODEOWNERS in root. + Path(f"{invalid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo with empty .github/CODEOWNERS. + Path(f"{invalid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + False, + invalid_codeowners_paths, + RepositoryCodeownersCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__repository_codeowners__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid CODEOWNERS file. + Note: Skipping this test as it is not implemented. + """ + pass + + +def test__repository_code_review_rules__is_always_skipped( + repo_info, beman_standard_check_config +): + """ + Test that repository.code_review_rules is always skipped. + """ + assert RepositoryCodeReviewRulesCheck( + repo_info, beman_standard_check_config + ).should_skip() + + +def test__repository_disallow_git_submodules__valid( + repo_info, beman_standard_check_config +): + """ + Test that repositories with valid git submodules pass the check. + """ + valid_submodules_paths = [ + # Repo with no .gitsubmodules file + Path(f"{valid_prefix}/repo-exemplar-v1/"), + # Repo with wg21 git submodule + Path(f"{valid_prefix}/repo-exemplar-v2/"), + # Repo with wg21 submodule but different path + Path(f"{valid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + True, + valid_submodules_paths, + RepositoryDisallowGitSubmodulesCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__repository_disallow_git_submodules__invalid( + repo_info, beman_standard_check_config +): + """ + Test that repositories with invalid git submodules fail the check. + """ + invalid_submodules_paths = [ + # Repository with a single non-wg21 submodule + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + # Repository with multiple submodules including wg21 + Path(f"{invalid_prefix}/repo-exemplar-v2/"), + # Repository with multiple non-wg21 submodules + Path(f"{invalid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + False, + invalid_submodules_paths, + RepositoryDisallowGitSubmodulesCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__repository_disallow_git_submodules__fix_inplace( + repo_info, beman_standard_check_config +): + """ + Test that the fix method corrects an invalid git submodules file. + Note: Skipping this test as it is not implemented. + """ + pass diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/conftest.py new file mode 100644 index 0000000..515dc2b --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/bla/LICENSE b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/bla/LICENSE new file mode 100644 index 0000000..e4fa6a8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/bla/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/cmake/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/cmake/CMakeLists.txt new file mode 100644 index 0000000..a4d1258 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/cmake/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/license/LICENSE b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/license/LICENSE new file mode 100644 index 0000000..e4fa6a8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/license/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/readme/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/readme/README.md new file mode 100644 index 0000000..19e661f --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/readme/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep new file mode 100644 index 0000000..e69de29 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/CMakeLists.txt b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/CMakeLists.txt new file mode 100644 index 0000000..a4d1258 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/LICENSE b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/LICENSE new file mode 100644 index 0000000..e4fa6a8 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/README.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/README.md new file mode 100644 index 0000000..19e661f --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py new file mode 100644 index 0000000..3581aa0 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest +from pathlib import Path + +from tests.utils.path_runners import ( + run_check_for_each_path, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.toplevel import ( + ToplevelCmakeCheck, + ToplevelLicenseCheck, + ToplevelReadmeCheck, +) + +test_data_prefix = "tests/lib/checks/beman_standard/toplevel/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" + + +def test__toplevel_cmake__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid CMakeLists.txt pass the check. + """ + valid_cmake_paths = [ + # exemplar/ repo with valid CMakeLists.txt file. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_cmake_paths, + ToplevelCmakeCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__toplevel_cmake__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid CMakeLists.txt fail the check. + """ + invalid_cmake_paths = [ + # exemplar/ repo with empty CMakeLists.txt file. + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with CMakeLists.txt in non-root location. + Path(f"{invalid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo without CMakeLists.txt file. + Path(f"{invalid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + False, + invalid_cmake_paths, + ToplevelCmakeCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__toplevel_cmake__fix_inplace(repo_info, beman_standard_check_config): + pass + + +def test__toplevel_license__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid LICENSE pass the check. + """ + valid_license_paths = [ + # exemplar/ repo with valid LICENSE file. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_license_paths, + ToplevelLicenseCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__toplevel_license__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid LICENSE fail the check. + """ + invalid_license_paths = [ + # exemplar/ repo with empty LICENSE file. + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with LICENSE in non-root location. + Path(f"{invalid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo without LICENSE file. + Path(f"{invalid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + False, + invalid_license_paths, + ToplevelLicenseCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__toplevel_license__fix_inplace(repo_info, beman_standard_check_config): + pass + + +def test__toplevel_readme__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid README.md pass the check. + """ + valid_readme_paths = [ + # exemplar/ repo with valid README.md file. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_readme_paths, + ToplevelReadmeCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__toplevel_readme__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid README.md fail the check. + """ + invalid_readme_paths = [ + # exemplar/ repo with empty README.md file. + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with README.md in non-root location. + Path(f"{invalid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo without README.md file. + Path(f"{invalid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + False, + invalid_readme_paths, + ToplevelReadmeCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="not implemented") +def test__toplevel_readme__fix_inplace(repo_info, beman_standard_check_config): + pass diff --git a/infra/tools/beman-tidy/tests/lib/checks/system/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/system/__init__.py new file mode 100644 index 0000000..1b5dbec --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/system/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception diff --git a/infra/tools/beman-tidy/tests/lib/checks/system/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/system/conftest.py new file mode 100644 index 0000000..3f30f80 --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/system/conftest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import pytest + +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 + + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): # noqa: F811 + return mock_repo_info + + +@pytest.fixture(autouse=True) +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 + return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/system/test_registry.py b/infra/tools/beman-tidy/tests/lib/checks/system/test_registry.py new file mode 100644 index 0000000..6f8603f --- /dev/null +++ b/infra/tools/beman-tidy/tests/lib/checks/system/test_registry.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import inspect +from pathlib import Path + +from beman_tidy.lib.checks.system.registry import ( + get_registered_beman_standard_checks, +) +from tests.utils.registry import ( + find_pytest_test_functions_for_check, + find_filename_for_check, +) + + +def test__get_registered_beman_standard_checks__valid( + repo_info, beman_standard_check_config +): + """ + Test that the get_registered_beman_standard_checks() function returns the correct checks + and verify that each registered check has corresponding pytest test functions. + """ + all_registered_checks = get_registered_beman_standard_checks() + for check_name, check_class in all_registered_checks.items(): + # Convert check name to test function pattern. + # e.g., "readme.title" -> "readme_title" + check_pattern = check_name.replace(".", "_") + + # Find the filename for the check class. + filename = find_filename_for_check(check_name) + expected_function_path = ( + Path(__file__).parent.parent.parent.parent + / "lib" + / "checks" + / "beman_standard" + / filename + / f"test_{filename}.py" + ) + assert filename is not None and expected_function_path.exists(), ( + f"[{check_name}] Missing file {expected_function_path}" + ) + + # Find all test functions that match the check name. + test_functions = find_pytest_test_functions_for_check(check_pattern) + + # Decide if the check is runnable or skipped. + check_instance = check_class(repo_info, beman_standard_check_config) + if check_instance.should_skip(): + # Skipped checks have exactly one test function. + expected_function_name = f"test__{check_pattern}__is_always_skipped" + assert len(test_functions) == 1, ( + f"[{check_name}] Expected exactly one test function for {check_name}: {expected_function_name} at {expected_function_path}" + ) + + actual_function_path = Path(test_functions[0]["file"]) + actual_function_name = test_functions[0]["function"] + + assert expected_function_path == actual_function_path, ( + f"[{check_name}] Test function path should match the expected pattern: {actual_function_path} != {expected_function_path}" + ) + assert expected_function_name == actual_function_name, ( + f"[{check_name}] Test function name should match the expected pattern: {actual_function_name} != {expected_function_name}" + ) + else: + # Runnable checks have exactly three test functions. + expected_function_names = [ + f"test__{check_pattern}__valid", + f"test__{check_pattern}__invalid", + f"test__{check_pattern}__fix_inplace", + ] + assert len(test_functions) == len(expected_function_names), ( + f"[{check_name}] Expected exactly three test functions for runnable check {check_name}: {expected_function_names} at {expected_function_path}" + ) + + for test_function in test_functions: + actual_function_path = Path(test_function["file"]) + actual_function_name = test_function["function"] + assert expected_function_path == actual_function_path, ( + f"[{check_name}] Test function path should match the expected pattern: {actual_function_path} != {expected_function_path}" + ) + assert any( + expected_function_name == actual_function_name + for expected_function_name in expected_function_names + ), ( + f"[{check_name}] Test function name should match the expected pattern: {actual_function_name} != {expected_function_name}" + ) + + +def test__registry_completeness__check(): + """ + Test that verifies the completeness of the registry system. + This is a comprehensive test of all registry functionality. + """ + from beman_tidy.lib.checks.system.registry import ( + get_all_beman_standard_check_names, + get_beman_standard_check_by_name, + get_beman_standard_check_name_by_class, + ) + + registered_checks = get_registered_beman_standard_checks() + registered_names = get_all_beman_standard_check_names() + + # Basic registry validation + assert len(registered_checks) > 0, "Registry should not be empty" + assert len(registered_names) == len(registered_checks), ( + "Names list and checks dict should have same length" + ) + + # Test each registry function + for check_name in registered_names: + # Test get_beman_standard_check_by_name. + check_class = get_beman_standard_check_by_name(check_name) + assert check_class is not None, ( + f"Should be able to retrieve check class for '{check_name}'" + ) + assert check_class == registered_checks[check_name], ( + "Retrieved class should match registry entry" + ) + + # Test get_beman_standard_check_name_by_class + reverse_name = get_beman_standard_check_name_by_class(check_class) + assert reverse_name == check_name, ( + f"Reverse lookup should work for '{check_name}'" + ) + + # Verify class structure. + assert inspect.isclass(check_class), ( + f"'{check_name}' should be registered to a class" + ) + assert hasattr(check_class, "check"), ( + f"'{check_name}' class should have 'check' method" + ) + assert hasattr(check_class, "fix"), ( + f"'{check_name}' class should have 'fix' method" + ) + + +def test__registry_no_duplicates__check(): + """ + Test that no check class is registered multiple times. + """ + registered_checks = get_registered_beman_standard_checks() + + # Create reverse mapping: class -> list of names. + class_to_names = {} + for check_name, check_class in registered_checks.items(): + if check_class not in class_to_names: + class_to_names[check_class] = [] + class_to_names[check_class].append(check_name) + + # Verify each class is only registered once + duplicates = [] + for check_class, check_names in class_to_names.items(): + if len(check_names) > 1: + duplicates.append((check_class.__name__, check_names)) + + assert len(duplicates) == 0, f"Found duplicate registrations: {duplicates}" diff --git a/infra/tools/beman-tidy/tests/utils/conftest.py b/infra/tools/beman-tidy/tests/utils/conftest.py index 71d82c0..99b6ed4 100644 --- a/infra/tools/beman-tidy/tests/utils/conftest.py +++ b/infra/tools/beman-tidy/tests/utils/conftest.py @@ -13,6 +13,7 @@ def mock_repo_info(): "name": "exemplar", "remote_url": "https://github.com/bemanproject/exemplar", "current_branch": "main", + "default_branch": "main", "commit_hash": 0, "status": "", "unstaged_changes": "", diff --git a/infra/tools/beman-tidy/tests/utils/path_runners.py b/infra/tools/beman-tidy/tests/utils/path_runners.py index e7b09ec..64535d6 100644 --- a/infra/tools/beman-tidy/tests/utils/path_runners.py +++ b/infra/tools/beman-tidy/tests/utils/path_runners.py @@ -5,6 +5,33 @@ from pathlib import Path +def run_check_for_each_repo_info( + expected_result, check_class, repo_infos, beman_standard_check_config +): + """ + Run repo-info-based check (check_class) for each given repo_info: evaluate check_class(repo_infos[i]). + + This is useful for checks that work with repository metadata rather than file paths. + + Example: + expected_result = True / False + repo_infos = [ + {"default_branch": "main", ...}, + {"default_branch": "master", ...}, + ] + check_class = RepositoryDefaultBranchCheck + beman_standard_check_config = "/path/to/.beman-standard.yml" + """ + for repo_info in repo_infos: + check_instance = check_class(repo_info, beman_standard_check_config) + check_instance.log_level = True + + # Run the main check + assert check_instance.check() is expected_result, ( + f"[{check_instance.__class__.__name__}] check() failed for repo_info: {repo_info}" + ) + + def run_check_for_each_path( expected_result, paths, check_class, repo_info, beman_standard_check_config ): @@ -22,13 +49,25 @@ def run_check_for_each_path( beman_standard_check_config = "/path/to/.beman-standard.yml" """ for path in paths: + if os.path.isdir(path): + # For repo checks, modify the repo_info to point to the test directory + repo_info["top_level"] = Path(path) + check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(path) + + if os.path.isfile(path): + # For file checks, set the path directly on the check instance + check_instance.path = Path(path) + check_instance.log_level = True - assert check_instance.pre_check() is True, ( - f"[{check_instance.__class__.__name__}] pre_check() failed for {path}" - ) + if os.path.isfile(path): + # For file-based checks, pre_check is expected to pass + assert check_instance.pre_check() is True, ( + f"[{check_instance.__class__.__name__}] pre_check() failed for {path}" + ) + + # Run the main check assert check_instance.check() is expected_result, ( f"[{check_instance.__class__.__name__}] check() failed for {path}" ) diff --git a/infra/tools/beman-tidy/tests/utils/registry.py b/infra/tools/beman-tidy/tests/utils/registry.py new file mode 100644 index 0000000..8b10b3f --- /dev/null +++ b/infra/tools/beman-tidy/tests/utils/registry.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import importlib +import inspect +from pathlib import Path +import re + + +def find_pytest_test_functions_for_check(check_pattern): + """ + Find all pytest test functions that match the given check pattern. + + Args: + check_pattern: The check pattern (e.g., "readme_title") + + Returns: + List of dictionaries containing module and function information + """ + # Search in beman_standard test directories + beman_standard_tests_dir = ( + Path(__file__).parent.parent / "lib" / "checks" / "beman_standard" + ) + if not beman_standard_tests_dir.exists(): + return [] + + test_functions = [] + # Iterate through all test modules in beman_standard + for category_dir in beman_standard_tests_dir.iterdir(): + if category_dir.is_dir() and not category_dir.name.startswith("__"): + test_file = category_dir / f"test_{category_dir.name}.py" + + if test_file.exists(): + # Import the test module + try: + module_name = f"tests.lib.checks.beman_standard.{category_dir.name}.test_{category_dir.name}" + spec = importlib.util.spec_from_file_location( + module_name, test_file + ) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + # Find test functions that match our pattern + for name, obj in inspect.getmembers(module): + if ( + inspect.isfunction(obj) + and name.startswith("test__") + and check_pattern in name + ): + test_functions.append( + { + "module": module_name, + "function": name, + "file": str(test_file), + "category": category_dir.name, + } + ) + + except Exception as e: + print(f"Error loading module {test_file}: {e}") + + return test_functions + + +def find_filename_for_check(check_name): + """ + Find the Python file that contains the check class for the given check name. + + Args: + check_name: The check name (e.g., "readme.title") + + Returns: + The filename of the check class + """ + # Search in beman_standard test directories + beman_standard_lib_dir = ( + Path(__file__).parent.parent.parent + / "beman_tidy" + / "lib" + / "checks" + / "beman_standard" + ) + if not beman_standard_lib_dir.exists(): + assert False, ( + f"Beman Standard library directory does not exist: {beman_standard_lib_dir}" + ) + return None + + # Find @register_beman_standard_check("{check_name}") inside the file + for file in beman_standard_lib_dir.glob("*.py"): + regex = r"@register_beman_standard_check\(\"{check_name}\"\)".format( + check_name=check_name + ) + with open(file, "r") as f: + if re.search(regex, f.read()): + return file.name.replace(".py", "") + + # If no file is found, return None. + assert False, f"No file found for {check_name} in {beman_standard_lib_dir}" + return None