From 00081e683894595145f04c75370b18a9cb1f719c Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:30:33 -0500 Subject: [PATCH 001/371] add toolchain --- cmake/toolchain.cmake | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 cmake/toolchain.cmake diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake new file mode 100644 index 00000000..60b4769a --- /dev/null +++ b/cmake/toolchain.cmake @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Toolchain file +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") + +# BEMAN_BUILDSYS_SANITIZER is not a general use option +# It is used by preset and CI system. +# There's three possible values: +# TSan: Thread sanitizer +# ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan +# OFF: No sanitizer + +if(DEFINED BEMAN_BUILDSYS_SANITIZER) + if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") + # Basic ASan flags + set(SANITIZER_FLAGS + "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) + + # Exclude -fsanitize=leak if using GCC on macOS + # TODO: Is there a way to detect Apple Clang??? + if( + CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + AND CMAKE_SYSTEM_NAME STREQUAL "Darwin" + ) + message(STATUS "Using GCC on macOS; excluding -fsanitize=leak") + else() + list(APPEND SANITIZER_FLAGS "-fsanitize=leak") + endif() + elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + set(SANITIZER_FLAGS "-fsanitize=thread") + elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") + set(SANITIZER_FLAGS "") + else() + message( + FATAL_ERROR + "Invalid BEMAN_BUILDSYS_SANITIZER option: ${BEMAN_BUILDSYS_SANITIZER}" + ) + endif() + + # Apply flags to both C and C++ compilers, along with debug settings + set(CMAKE_C_FLAGS_DEBUG_INIT + "${CMAKE_C_FLAGS_DEBUG_INIT} ${SANITIZER_FLAGS}" + ) + set(CMAKE_CXX_FLAGS_DEBUG_INIT + "${CMAKE_C_FLAGS_DEBUG_INIT} ${SANITIZER_FLAGS}" + ) +endif() From 71f36fbca30cc595b58a5387a3f16c9dcebb7e86 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:41:58 -0500 Subject: [PATCH 002/371] fix toolchain --- cmake/toolchain.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake index 60b4769a..77d6b54e 100644 --- a/cmake/toolchain.cmake +++ b/cmake/toolchain.cmake @@ -26,9 +26,10 @@ if(DEFINED BEMAN_BUILDSYS_SANITIZER) ) message(STATUS "Using GCC on macOS; excluding -fsanitize=leak") else() - list(APPEND SANITIZER_FLAGS "-fsanitize=leak") + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=leak") endif() elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + # Basic ASan flags set(SANITIZER_FLAGS "-fsanitize=thread") elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") set(SANITIZER_FLAGS "") @@ -39,7 +40,6 @@ if(DEFINED BEMAN_BUILDSYS_SANITIZER) ) endif() - # Apply flags to both C and C++ compilers, along with debug settings set(CMAKE_C_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBUG_INIT} ${SANITIZER_FLAGS}" ) From 091446153fcda3b726ac37961f12e4aeb19d51c4 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:18:54 -0500 Subject: [PATCH 003/371] update action script --- cmake/toolchain.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake index 77d6b54e..8d01d9e2 100644 --- a/cmake/toolchain.cmake +++ b/cmake/toolchain.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# Toolchain file +set(CMAKE_C_FLAGS_RELEASE_INIT "-O3") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3") + set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") From 997a13bce4cfd89165efca3936f994fb03af69dc Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 14 Nov 2024 17:36:14 -0500 Subject: [PATCH 004/371] Update toolchain.cmake --- cmake/toolchain.cmake | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake index 8d01d9e2..b3cd1280 100644 --- a/cmake/toolchain.cmake +++ b/cmake/toolchain.cmake @@ -20,12 +20,8 @@ if(DEFINED BEMAN_BUILDSYS_SANITIZER) "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) - # Exclude -fsanitize=leak if using GCC on macOS - # TODO: Is there a way to detect Apple Clang??? - if( - CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - AND CMAKE_SYSTEM_NAME STREQUAL "Darwin" - ) + # Exclude -fsanitize=leak on Apple Clang (gcc on macos) as it is not supported. + if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") message(STATUS "Using GCC on macOS; excluding -fsanitize=leak") else() set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=leak") From da702aecbe3467243d29569490c02a9fcd2d5562 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:51:49 -0500 Subject: [PATCH 005/371] give up using toolchain --- cmake/apply_santizers.cmake | 37 +++++++++++++++++++++++++++++ cmake/toolchain.cmake | 47 ------------------------------------- 2 files changed, 37 insertions(+), 47 deletions(-) create mode 100644 cmake/apply_santizers.cmake delete mode 100644 cmake/toolchain.cmake diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake new file mode 100644 index 00000000..30e2d3f7 --- /dev/null +++ b/cmake/apply_santizers.cmake @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# BEMAN_BUILDSYS_SANITIZER is not a general use option +# It is used by preset and CI system. +# There's three possible values: +# TSan: Thread sanitizer +# ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan +# OFF: No sanitizer + +message("Applying sanitizers for ${CMAKE_CXX_COMPILER_ID}") + +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") + # Basic ASan flags + set(SANITIZER_FLAGS + "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) + + # Exclude -fsanitize=leak on Apple Clang (gcc on macos) as it is not supported. + if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + message(STATUS "Using GCC on macOS; excluding -fsanitize=leak") + else() + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=leak") + endif() +elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + # Basic ASan flags + set(SANITIZER_FLAGS "-fsanitize=thread") +elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") + set(SANITIZER_FLAGS "") +else() + message( + FATAL_ERROR + "Invalid BEMAN_BUILDSYS_SANITIZER option: ${BEMAN_BUILDSYS_SANITIZER}" + ) +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake deleted file mode 100644 index b3cd1280..00000000 --- a/cmake/toolchain.cmake +++ /dev/null @@ -1,47 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -set(CMAKE_C_FLAGS_RELEASE_INIT "-O3") -set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3") - -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") - -# BEMAN_BUILDSYS_SANITIZER is not a general use option -# It is used by preset and CI system. -# There's three possible values: -# TSan: Thread sanitizer -# ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan -# OFF: No sanitizer - -if(DEFINED BEMAN_BUILDSYS_SANITIZER) - if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") - # Basic ASan flags - set(SANITIZER_FLAGS - "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" - ) - - # Exclude -fsanitize=leak on Apple Clang (gcc on macos) as it is not supported. - if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - message(STATUS "Using GCC on macOS; excluding -fsanitize=leak") - else() - set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=leak") - endif() - elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") - # Basic ASan flags - set(SANITIZER_FLAGS "-fsanitize=thread") - elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") - set(SANITIZER_FLAGS "") - else() - message( - FATAL_ERROR - "Invalid BEMAN_BUILDSYS_SANITIZER option: ${BEMAN_BUILDSYS_SANITIZER}" - ) - endif() - - set(CMAKE_C_FLAGS_DEBUG_INIT - "${CMAKE_C_FLAGS_DEBUG_INIT} ${SANITIZER_FLAGS}" - ) - set(CMAKE_CXX_FLAGS_DEBUG_INIT - "${CMAKE_C_FLAGS_DEBUG_INIT} ${SANITIZER_FLAGS}" - ) -endif() From fda3c6bb001201cd5d1328a4c41e3efde736f9f7 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 15 Nov 2024 01:03:41 -0500 Subject: [PATCH 006/371] refactor apply_santizers --- cmake/apply_santizers.cmake | 39 ++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake index 30e2d3f7..fa8da825 100644 --- a/cmake/apply_santizers.cmake +++ b/cmake/apply_santizers.cmake @@ -10,20 +10,45 @@ message("Applying sanitizers for ${CMAKE_CXX_COMPILER_ID}") if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") - # Basic ASan flags - set(SANITIZER_FLAGS + set(_ASAN_ADDR "-fsanitize=address") + set(_ASAN_LEAK "-fsanitize=leak") + set(_ASAN_MISC "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) - # Exclude -fsanitize=leak on Apple Clang (gcc on macos) as it is not supported. + # Exclude -fsanitize=leak on Apple Clang as it is not supported. if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - message(STATUS "Using GCC on macOS; excluding -fsanitize=leak") + message(STATUS "Using AppleClang; excluding -fsanitize=leak") + set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_MISC}") + # Only include Address sanitizer on MSVC + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + message(STATUS "Using MSVC; only Address sanitizer is set") + set(SANITIZER_FLAGS _ASAN_ADDR) + # We are able to enable all sanitizers on Clang and GNU + elseif( + CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + ) + set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_LEAK} ${_ASAN_MISC}") else() - set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=leak") + message( + STATUS + "Unknown compiler ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + ) endif() elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") - # Basic ASan flags - set(SANITIZER_FLAGS "-fsanitize=thread") + # Basic TSan flags + if( + CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + ) + set(SANITIZER_FLAGS "-fsanitize=thread") + else() + message( + STATUS + "TSan not supported/ Unknown compiler: ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + ) + endif() elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") set(SANITIZER_FLAGS "") else() From 6d0ee72344538829ba56f738f4be4665d4532c08 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 26 Nov 2024 02:18:37 -0500 Subject: [PATCH 007/371] tweak for msvc --- cmake/apply_santizers.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake index fa8da825..64835964 100644 --- a/cmake/apply_santizers.cmake +++ b/cmake/apply_santizers.cmake @@ -20,10 +20,10 @@ if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") message(STATUS "Using AppleClang; excluding -fsanitize=leak") set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_MISC}") - # Only include Address sanitizer on MSVC + # Only include Address sanitizer on MSVC, debug info must be included for MSVC to work elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") message(STATUS "Using MSVC; only Address sanitizer is set") - set(SANITIZER_FLAGS _ASAN_ADDR) + set(SANITIZER_FLAGS "/fsanitize=address /Zi") # We are able to enable all sanitizers on Clang and GNU elseif( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" From 475ac8776c375a79ceaaf75c40ca91d6332e0df0 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 26 Nov 2024 02:19:13 -0500 Subject: [PATCH 008/371] warp apply_santizers.cmake in ifdef --- cmake/apply_santizers.cmake | 92 +++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake index 64835964..e4693ba6 100644 --- a/cmake/apply_santizers.cmake +++ b/cmake/apply_santizers.cmake @@ -7,56 +7,58 @@ # ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan # OFF: No sanitizer -message("Applying sanitizers for ${CMAKE_CXX_COMPILER_ID}") +if(DEFINED BEMAN_BUILDSYS_SANITIZER) + message("Applying sanitizers for ${CMAKE_CXX_COMPILER_ID}") -if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") - set(_ASAN_ADDR "-fsanitize=address") - set(_ASAN_LEAK "-fsanitize=leak") - set(_ASAN_MISC - "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" - ) + if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") + set(_ASAN_ADDR "-fsanitize=address") + set(_ASAN_LEAK "-fsanitize=leak") + set(_ASAN_MISC + "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) - # Exclude -fsanitize=leak on Apple Clang as it is not supported. - if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - message(STATUS "Using AppleClang; excluding -fsanitize=leak") - set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_MISC}") - # Only include Address sanitizer on MSVC, debug info must be included for MSVC to work - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - message(STATUS "Using MSVC; only Address sanitizer is set") - set(SANITIZER_FLAGS "/fsanitize=address /Zi") - # We are able to enable all sanitizers on Clang and GNU - elseif( - CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - ) - set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_LEAK} ${_ASAN_MISC}") - else() - message( - STATUS - "Unknown compiler ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + # Exclude -fsanitize=leak on Apple Clang as it is not supported. + if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + message(STATUS "Using AppleClang; excluding -fsanitize=leak") + set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_MISC}") + # Only include Address sanitizer on MSVC, debug info must be included for MSVC to work + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + message(STATUS "Using MSVC; only Address sanitizer is set") + set(SANITIZER_FLAGS "/fsanitize=address /Zi") + # We are able to enable all sanitizers on Clang and GNU + elseif( + CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" ) - endif() -elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") - # Basic TSan flags - if( - CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - ) - set(SANITIZER_FLAGS "-fsanitize=thread") + set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_LEAK} ${_ASAN_MISC}") + else() + message( + STATUS + "Unknown compiler ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + ) + endif() + elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + # Basic TSan flags + if( + CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + ) + set(SANITIZER_FLAGS "-fsanitize=thread") + else() + message( + STATUS + "TSan not supported/ Unknown compiler: ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + ) + endif() + elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") + set(SANITIZER_FLAGS "") else() message( - STATUS - "TSan not supported/ Unknown compiler: ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + FATAL_ERROR + "Invalid BEMAN_BUILDSYS_SANITIZER option: ${BEMAN_BUILDSYS_SANITIZER}" ) endif() -elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") - set(SANITIZER_FLAGS "") -else() - message( - FATAL_ERROR - "Invalid BEMAN_BUILDSYS_SANITIZER option: ${BEMAN_BUILDSYS_SANITIZER}" - ) -endif() -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAGS}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") +endif() From 526505163b81e698d44db828c2c9596fcef13cad Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:43:43 -0500 Subject: [PATCH 009/371] extract sanitizer generation as function --- cmake/apply_santizers.cmake | 50 ++++++++++++++----------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake index e4693ba6..391fb5a8 100644 --- a/cmake/apply_santizers.cmake +++ b/cmake/apply_santizers.cmake @@ -7,58 +7,46 @@ # ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan # OFF: No sanitizer -if(DEFINED BEMAN_BUILDSYS_SANITIZER) - message("Applying sanitizers for ${CMAKE_CXX_COMPILER_ID}") - - if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") +function(GENERATE_SANITIZER_PARAM KIND COMPILER_ID SANITIZER_FLAGS) + if(${KIND} STREQUAL "ASan") set(_ASAN_ADDR "-fsanitize=address") set(_ASAN_LEAK "-fsanitize=leak") set(_ASAN_MISC "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) - # Exclude -fsanitize=leak on Apple Clang as it is not supported. - if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + if(${COMPILER_ID} STREQUAL "AppleClang") + # Exclude -fsanitize=leak on Apple Clang as it is not supported. message(STATUS "Using AppleClang; excluding -fsanitize=leak") - set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_MISC}") + set(RES "${_ASAN_ADDR} ${_ASAN_MISC}") + elseif(${COMPILER_ID} STREQUAL "MSVC") # Only include Address sanitizer on MSVC, debug info must be included for MSVC to work - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") message(STATUS "Using MSVC; only Address sanitizer is set") - set(SANITIZER_FLAGS "/fsanitize=address /Zi") + set(RES "/fsanitize=address /Zi") + elseif(${COMPILER_ID} STREQUAL "Clang" OR ${COMPILER_ID} STREQUAL "GNU") # We are able to enable all sanitizers on Clang and GNU - elseif( - CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - ) - set(SANITIZER_FLAGS "${_ASAN_ADDR} ${_ASAN_LEAK} ${_ASAN_MISC}") + set(RES "${_ASAN_ADDR} ${_ASAN_LEAK} ${_ASAN_MISC}") else() message( STATUS - "Unknown compiler ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + "Unknown compiler ${${COMPILER_ID}}, no sanitizer is set" ) endif() - elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + elseif(KIND STREQUAL "TSan") # Basic TSan flags - if( - CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - ) - set(SANITIZER_FLAGS "-fsanitize=thread") + if(${COMPILER_ID} STREQUAL "Clang" OR ${COMPILER_ID} STREQUAL "GNU") + set(RES "-fsanitize=thread") else() message( STATUS - "TSan not supported/ Unknown compiler: ${CMAKE_CXX_COMPILER_ID}, no sanitizer is set" + "TSan not supported/ Unknown compiler: ${${COMPILER_ID}}, no sanitizer is set" ) endif() - elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "OFF") - set(SANITIZER_FLAGS "") + elseif(KIND STREQUAL "OFF") + set(RES "") else() - message( - FATAL_ERROR - "Invalid BEMAN_BUILDSYS_SANITIZER option: ${BEMAN_BUILDSYS_SANITIZER}" - ) + message(FATAL_ERROR "Invalid Sanitizer class kind option: ${KIND}") endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") -endif() + set(${SANITIZER_FLAGS} ${RES} PARENT_SCOPE) +endfunction() From db05fccd88965a34ff4add4077accba7c35632b9 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:45:27 -0500 Subject: [PATCH 010/371] update comment --- cmake/apply_santizers.cmake | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake index 391fb5a8..dfbdf37a 100644 --- a/cmake/apply_santizers.cmake +++ b/cmake/apply_santizers.cmake @@ -1,12 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# BEMAN_BUILDSYS_SANITIZER is not a general use option -# It is used by preset and CI system. # There's three possible values: # TSan: Thread sanitizer # ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan # OFF: No sanitizer - function(GENERATE_SANITIZER_PARAM KIND COMPILER_ID SANITIZER_FLAGS) if(${KIND} STREQUAL "ASan") set(_ASAN_ADDR "-fsanitize=address") From 931d6bb01fa48b65648acf74969b10b4fe1584a1 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:25:25 -0500 Subject: [PATCH 011/371] use toolchain --- cmake/gnu-toolchain.cmake | 18 ++++++++++++++++++ cmake/llvm-toolchain.cmake | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 cmake/gnu-toolchain.cmake create mode 100644 cmake/llvm-toolchain.cmake diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake new file mode 100644 index 00000000..4f3a3a22 --- /dev/null +++ b/cmake/gnu-toolchain.cmake @@ -0,0 +1,18 @@ +set(CMAKE_C_COMPILER gcc) +set(CMAKE_CXX_COMPILER g++) +set(CMAKE_GENERATOR "Ninja Multi-Config") + +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") + set(CMAKE_CXX_FLAGS_DEBUG_INIT + "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) + set(CMAKE_C_FLAGS_DEBUG_INIT + "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) +elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=thread") + set(CMAKE_C_FLAGS_DEBUG_INIT "-fsanitize=thread") +endif() + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake new file mode 100644 index 00000000..5cc375c3 --- /dev/null +++ b/cmake/llvm-toolchain.cmake @@ -0,0 +1,18 @@ +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_GENERATOR "Ninja Multi-Config") + +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") + set(CMAKE_CXX_FLAGS_DEBUG_INIT + "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) + set(CMAKE_C_FLAGS_DEBUG_INIT + "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) +elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=thread") + set(CMAKE_C_FLAGS_DEBUG_INIT "-fsanitize=thread") +endif() + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") From 9f471295519b8348f40eb9172317827c5ddf5bf1 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:31:10 -0500 Subject: [PATCH 012/371] move generator out --- cmake/gnu-toolchain.cmake | 1 - cmake/llvm-toolchain.cmake | 1 - 2 files changed, 2 deletions(-) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index 4f3a3a22..b17ddef2 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -1,6 +1,5 @@ set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) -set(CMAKE_GENERATOR "Ninja Multi-Config") if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") set(CMAKE_CXX_FLAGS_DEBUG_INIT diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index 5cc375c3..afcfe3f6 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -1,6 +1,5 @@ set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) -set(CMAKE_GENERATOR "Ninja Multi-Config") if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") set(CMAKE_CXX_FLAGS_DEBUG_INIT From cabf5fddc0277918a0b4725087624649898e0ade Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:40:41 -0500 Subject: [PATCH 013/371] remove cmake/apply_santizers.cmake --- cmake/apply_santizers.cmake | 49 ------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 cmake/apply_santizers.cmake diff --git a/cmake/apply_santizers.cmake b/cmake/apply_santizers.cmake deleted file mode 100644 index dfbdf37a..00000000 --- a/cmake/apply_santizers.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# There's three possible values: -# TSan: Thread sanitizer -# ASan: All sanitizer (majorly Address sanitizer) that doesn't conflict with TSan -# OFF: No sanitizer -function(GENERATE_SANITIZER_PARAM KIND COMPILER_ID SANITIZER_FLAGS) - if(${KIND} STREQUAL "ASan") - set(_ASAN_ADDR "-fsanitize=address") - set(_ASAN_LEAK "-fsanitize=leak") - set(_ASAN_MISC - "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" - ) - - if(${COMPILER_ID} STREQUAL "AppleClang") - # Exclude -fsanitize=leak on Apple Clang as it is not supported. - message(STATUS "Using AppleClang; excluding -fsanitize=leak") - set(RES "${_ASAN_ADDR} ${_ASAN_MISC}") - elseif(${COMPILER_ID} STREQUAL "MSVC") - # Only include Address sanitizer on MSVC, debug info must be included for MSVC to work - message(STATUS "Using MSVC; only Address sanitizer is set") - set(RES "/fsanitize=address /Zi") - elseif(${COMPILER_ID} STREQUAL "Clang" OR ${COMPILER_ID} STREQUAL "GNU") - # We are able to enable all sanitizers on Clang and GNU - set(RES "${_ASAN_ADDR} ${_ASAN_LEAK} ${_ASAN_MISC}") - else() - message( - STATUS - "Unknown compiler ${${COMPILER_ID}}, no sanitizer is set" - ) - endif() - elseif(KIND STREQUAL "TSan") - # Basic TSan flags - if(${COMPILER_ID} STREQUAL "Clang" OR ${COMPILER_ID} STREQUAL "GNU") - set(RES "-fsanitize=thread") - else() - message( - STATUS - "TSan not supported/ Unknown compiler: ${${COMPILER_ID}}, no sanitizer is set" - ) - endif() - elseif(KIND STREQUAL "OFF") - set(RES "") - else() - message(FATAL_ERROR "Invalid Sanitizer class kind option: ${KIND}") - endif() - - set(${SANITIZER_FLAGS} ${RES} PARENT_SCOPE) -endfunction() From de10ecff88677e31c6abe0a2c1850ee1f03a24af Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:45:47 -0500 Subject: [PATCH 014/371] add msvc toolchain --- cmake/msvc-toolchain.cmake | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 cmake/msvc-toolchain.cmake diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake new file mode 100644 index 00000000..3d9e3d9e --- /dev/null +++ b/cmake/msvc-toolchain.cmake @@ -0,0 +1,15 @@ +set(CMAKE_C_COMPILER cl) +set(CMAKE_CXX_COMPILER cl) + +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") + set(CMAKE_CXX_FLAGS_DEBUG_INIT "/fsanitize=address /Zi") + set(CMAKE_C_FLAGS_DEBUG_INIT "/fsanitize=address /Zi") +endif() + +set(CMAKE_CXX_FLAGS_DEBUG_INIT + "${CMAKE_CXX_FLAGS_DEBUG_INIT} /EHsc /permissive-" +) +set(CMAKE_C_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBUG_INIT} /EHsc /permissive-") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/EHsc /permissive- /O2") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/EHsc /permissive- /O2") From f925411573d063a44658ec1b8dad2278d03dd035 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 14 Dec 2024 19:07:44 -0500 Subject: [PATCH 015/371] apply license --- cmake/gnu-toolchain.cmake | 2 ++ cmake/llvm-toolchain.cmake | 2 ++ cmake/msvc-toolchain.cmake | 2 ++ 3 files changed, 6 insertions(+) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index b17ddef2..b4dc0f69 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index afcfe3f6..db305150 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 3d9e3d9e..cb6f8897 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + set(CMAKE_C_COMPILER cl) set(CMAKE_CXX_COMPILER cl) From e83824c617a68ca34ff252a139e78d45d6edf388 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:09:57 -0500 Subject: [PATCH 016/371] adopt include guard --- cmake/gnu-toolchain.cmake | 2 ++ cmake/llvm-toolchain.cmake | 2 ++ cmake/msvc-toolchain.cmake | 2 ++ 3 files changed, 6 insertions(+) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index b4dc0f69..2b74d5c2 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +include_guard(GLOBAL) + set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index db305150..debacef1 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +include_guard(GLOBAL) + set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index cb6f8897..0f40ba7c 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +include_guard(GLOBAL) + set(CMAKE_C_COMPILER cl) set(CMAKE_CXX_COMPILER cl) From 30981d42bc63a844198a7ba0959d381a32a35785 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:50:45 -0500 Subject: [PATCH 017/371] apply sanitizer to all targets --- cmake/gnu-toolchain.cmake | 15 +++++++-------- cmake/llvm-toolchain.cmake | 15 +++++++-------- cmake/msvc-toolchain.cmake | 17 +++++++++-------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index 2b74d5c2..e6ad701a 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -6,16 +6,15 @@ set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") - set(CMAKE_CXX_FLAGS_DEBUG_INIT - "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" - ) - set(CMAKE_C_FLAGS_DEBUG_INIT + set(SANITIZER_FLAGS "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") - set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=thread") - set(CMAKE_C_FLAGS_DEBUG_INIT "-fsanitize=thread") + set(SANITIZER_FLAGS "-fsanitize=thread") endif() -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") +set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") +set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index debacef1..4029ae9a 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -6,16 +6,15 @@ set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") - set(CMAKE_CXX_FLAGS_DEBUG_INIT - "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" - ) - set(CMAKE_C_FLAGS_DEBUG_INIT + set(SANITIZER_FLAGS "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") - set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=thread") - set(CMAKE_C_FLAGS_DEBUG_INIT "-fsanitize=thread") + set(SANITIZER_FLAGS "-fsanitize=thread") endif() -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3") +set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") +set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 0f40ba7c..9f96cba3 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -6,14 +6,15 @@ set(CMAKE_C_COMPILER cl) set(CMAKE_CXX_COMPILER cl) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") - set(CMAKE_CXX_FLAGS_DEBUG_INIT "/fsanitize=address /Zi") - set(CMAKE_C_FLAGS_DEBUG_INIT "/fsanitize=address /Zi") + set(SANITIZER_FLAGS "/fsanitize=address /Zi") endif() -set(CMAKE_CXX_FLAGS_DEBUG_INIT - "${CMAKE_CXX_FLAGS_DEBUG_INIT} /EHsc /permissive-" -) -set(CMAKE_C_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBUG_INIT} /EHsc /permissive-") +set(CMAKE_CXX_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") +set(CMAKE_C_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/EHsc /permissive- /O2") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/EHsc /permissive- /O2") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT + "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}" +) +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT + "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}" +) From 0438616903f3a39b642982ba8e18b0a572dd2fbb Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:58:54 -0500 Subject: [PATCH 018/371] update all release targets --- cmake/gnu-toolchain.cmake | 9 +++++++-- cmake/llvm-toolchain.cmake | 9 +++++++-- cmake/msvc-toolchain.cmake | 13 +++++++------ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index e6ad701a..eca1eeb7 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -16,5 +16,10 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") + +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index 4029ae9a..7015b769 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -16,5 +16,10 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") + +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 9f96cba3..23e650c4 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -12,9 +12,10 @@ endif() set(CMAKE_CXX_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") set(CMAKE_C_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT - "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}" -) -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT - "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}" -) +set(RELEASE_FLAG "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") + +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") From 12559d4573ef6200cf1db2e71315dd5b1fc1acbe Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:04:13 -0500 Subject: [PATCH 019/371] asan -> maxsan --- cmake/gnu-toolchain.cmake | 2 +- cmake/llvm-toolchain.cmake | 2 +- cmake/msvc-toolchain.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index eca1eeb7..df837fd3 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -5,7 +5,7 @@ include_guard(GLOBAL) set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) -if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index 7015b769..670f4043 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -5,7 +5,7 @@ include_guard(GLOBAL) set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) -if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" ) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 23e650c4..d0157ec5 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -5,7 +5,7 @@ include_guard(GLOBAL) set(CMAKE_C_COMPILER cl) set(CMAKE_CXX_COMPILER cl) -if(BEMAN_BUILDSYS_SANITIZER STREQUAL "ASan") +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS "/fsanitize=address /Zi") endif() From 18cd51340f65909a9973900f2f411845f3cb12d6 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sun, 22 Dec 2024 13:24:24 -0500 Subject: [PATCH 020/371] add documentation --- cmake/gnu-toolchain.cmake | 13 +++++++++++++ cmake/llvm-toolchain.cmake | 13 +++++++++++++ cmake/msvc-toolchain.cmake | 15 +++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index df837fd3..184338b9 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -1,5 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# This toolchain file is not meant to be used directly, +# but to be invoked by CMake preset and GitHub CI. +# +# This toolchain file configures for GNU family of compiler. +# +# BEMAN_BUILDSYS_SANITIZER: +# This optional CMake parameter is not meant for public use and is subject to +# change. +# Possible values: +# - MaxSan: configures gcc and g++ to use all available non-conflicting +# sanitizers. +# - TSan: configures gcc and g++ to enable the use of thread sanitizer + include_guard(GLOBAL) set(CMAKE_C_COMPILER gcc) diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index 670f4043..e30dd4dc 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -1,5 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# This toolchain file is not meant to be used directly, +# but to be invoked by CMake preset and GitHub CI. +# +# This toolchain file configures for LLVM family of compiler. +# +# BEMAN_BUILDSYS_SANITIZER: +# This optional CMake parameter is not meant for public use and is subject to +# change. +# Possible values: +# - MaxSan: configures clang and clang++ to use all available non-conflicting +# sanitizers. +# - TSan: configures clang and clang++ to enable the use of thread sanitizer. + include_guard(GLOBAL) set(CMAKE_C_COMPILER clang) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index d0157ec5..11c83824 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -1,5 +1,20 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# This toolchain file is not meant to be used directly, +# but to be invoked by CMake preset and GitHub CI. +# +# This toolchain file configures for MSVC family of compiler. +# +# BEMAN_BUILDSYS_SANITIZER: +# This optional CMake parameter is not meant for public use and is subject to +# change. +# Possible values: +# - MaxSan: configures cl to use all available non-conflicting sanitizers. +# +# Note that in other toolchain files, TSan is also a possible value for +# BEMAN_BUILDSYS_SANITIZER, however, MSVC does not support thread sanitizer, +# thus this value is omitted. + include_guard(GLOBAL) set(CMAKE_C_COMPILER cl) From 6456fadef123e311e83eb38ad9852e2eecf8f7ac Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Mon, 23 Dec 2024 19:17:42 -0500 Subject: [PATCH 021/371] remove unneeded include guard --- cmake/gnu-toolchain.cmake | 2 -- cmake/llvm-toolchain.cmake | 2 -- cmake/msvc-toolchain.cmake | 2 -- 3 files changed, 6 deletions(-) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index 184338b9..4b3c3639 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -13,8 +13,6 @@ # sanitizers. # - TSan: configures gcc and g++ to enable the use of thread sanitizer -include_guard(GLOBAL) - set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index e30dd4dc..5a2a1c11 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -13,8 +13,6 @@ # sanitizers. # - TSan: configures clang and clang++ to enable the use of thread sanitizer. -include_guard(GLOBAL) - set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 11c83824..67f28b39 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -15,8 +15,6 @@ # BEMAN_BUILDSYS_SANITIZER, however, MSVC does not support thread sanitizer, # thus this value is omitted. -include_guard(GLOBAL) - set(CMAKE_C_COMPILER cl) set(CMAKE_CXX_COMPILER cl) From eee29a3bdc9744ec7c76443f3d50ce2bb9c149f9 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 24 Dec 2024 21:42:50 -0500 Subject: [PATCH 022/371] update use of toolchain for appleclang and msvc --- cmake/appleclang-toolchain.cmake | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 cmake/appleclang-toolchain.cmake diff --git a/cmake/appleclang-toolchain.cmake b/cmake/appleclang-toolchain.cmake new file mode 100644 index 00000000..c915b245 --- /dev/null +++ b/cmake/appleclang-toolchain.cmake @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# This toolchain file is not meant to be used directly, +# but to be invoked by CMake preset and GitHub CI. +# +# This toolchain file configures for apple clang family of compiler. +# Note this is different from LLVM toolchain. +# +# BEMAN_BUILDSYS_SANITIZER: +# This optional CMake parameter is not meant for public use and is subject to +# change. +# Possible values: +# - MaxSan: configures clang and clang++ to use all available non-conflicting +# sanitizers. Note that apple clang does not support leak sanitizer. +# - TSan: configures clang and clang++ to enable the use of thread sanitizer. + +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) + +if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") + set(SANITIZER_FLAGS + "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + ) +elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") + set(SANITIZER_FLAGS "-fsanitize=thread") +endif() + +set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") +set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") + +set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") + +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") From 5c7f8da1e3062bbc5726a2c8e41fe559cddb5ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 27 Dec 2024 21:18:37 +0200 Subject: [PATCH 023/371] Initial commit --- .gitignore | 32 ++++++++++++++++++++++++++++++++ README.md | 2 ++ 2 files changed, 34 insertions(+) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..259148fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/README.md b/README.md new file mode 100644 index 00000000..20b85397 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# infra +Internal Beman Project infrastructure repo From c05ce19a9162bde2c35251a7d3ab3da928b071aa Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:57:45 -0500 Subject: [PATCH 024/371] RELEASE_FLAG -> RELEASE_FLAGS --- cmake/appleclang-toolchain.cmake | 10 +++++----- cmake/gnu-toolchain.cmake | 10 +++++----- cmake/llvm-toolchain.cmake | 10 +++++----- cmake/msvc-toolchain.cmake | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/cmake/appleclang-toolchain.cmake b/cmake/appleclang-toolchain.cmake index c915b245..eee6406a 100644 --- a/cmake/appleclang-toolchain.cmake +++ b/cmake/appleclang-toolchain.cmake @@ -28,10 +28,10 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") -set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index 4b3c3639..9d91ddd4 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -27,10 +27,10 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") -set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index 5a2a1c11..6ba5f80d 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -27,10 +27,10 @@ endif() set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}") -set(RELEASE_FLAG "-O3 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") -set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 67f28b39..5ca67b75 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -25,10 +25,10 @@ endif() set(CMAKE_CXX_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") set(CMAKE_C_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}") -set(RELEASE_FLAG "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}") +set(RELEASE_FLAGS "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") -set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") -set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAG}") +set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") From b76f790018aa481b1db806a0b548a8e3a8d831e6 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:27:16 -0500 Subject: [PATCH 025/371] add documentation for /Zi flag --- cmake/msvc-toolchain.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index 5ca67b75..cf5b5334 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -19,6 +19,8 @@ set(CMAKE_C_COMPILER cl) 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 "/fsanitize=address /Zi") endif() From 3f13a5f7bec670a2b40f679e3c1e0de894bf3962 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 11 Jan 2025 04:09:29 +0000 Subject: [PATCH 026/371] Readd include guard This reverts commit 6456fadef123e311e83eb38ad9852e2eecf8f7ac. --- cmake/gnu-toolchain.cmake | 2 ++ cmake/llvm-toolchain.cmake | 2 ++ cmake/msvc-toolchain.cmake | 2 ++ 3 files changed, 6 insertions(+) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index 9d91ddd4..2e2a2ad2 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -13,6 +13,8 @@ # sanitizers. # - TSan: configures gcc and g++ to enable the use of thread sanitizer +include_guard(GLOBAL) + set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index 6ba5f80d..d783803b 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -13,6 +13,8 @@ # sanitizers. # - TSan: configures clang and clang++ to enable the use of thread sanitizer. +include_guard(GLOBAL) + set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake index cf5b5334..c2fffa79 100644 --- a/cmake/msvc-toolchain.cmake +++ b/cmake/msvc-toolchain.cmake @@ -15,6 +15,8 @@ # BEMAN_BUILDSYS_SANITIZER, however, MSVC does not support thread sanitizer, # thus this value is omitted. +include_guard(GLOBAL) + set(CMAKE_C_COMPILER cl) set(CMAKE_CXX_COMPILER cl) From 2e840936768f31708747a96e88b27b022d84f1c5 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 11 Jan 2025 04:10:38 +0000 Subject: [PATCH 027/371] add include guard for appleclang-toolchain --- cmake/appleclang-toolchain.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/appleclang-toolchain.cmake b/cmake/appleclang-toolchain.cmake index eee6406a..bc12103d 100644 --- a/cmake/appleclang-toolchain.cmake +++ b/cmake/appleclang-toolchain.cmake @@ -14,6 +14,8 @@ # sanitizers. Note that apple clang does not support leak sanitizer. # - TSan: configures clang and clang++ to enable the use of thread sanitizer. +include_guard(GLOBAL) + set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) From 5edb73ac10c40255dd1bb486d516432f82c76d74 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 22 Jan 2025 09:40:48 +0200 Subject: [PATCH 028/371] Add skel for infra repo --- .github/CODEOWNERS | 4 + LICENSE | 218 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 13 ++- 3 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 LICENSE diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..ca6c395b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# Codeowners for reviews on PRs + +* @neatudarius @dietmarkuehl @JeffGarland @camio @inbal2l diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..537293d6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,218 @@ + 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/README.md b/README.md index 20b85397..dae43132 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,11 @@ -# infra -Internal Beman Project infrastructure repo +# Beman Project Infrastructure Repository + + + +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. + +## Description + +* `tools/`: Tools used to manage the infrastructure and the codebase (e.g., linting, formatting, etc.). From fad52c5a7ba3200bcba9650ee7db56a43da106f1 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 22 Jan 2025 09:47:35 +0200 Subject: [PATCH 029/371] beman-tidy: add skel --- .markdownlint.yaml | 9 +++++++++ tools/beman-tidy/README.md | 22 ++++++++++++++++++++++ tools/beman-tidy/beman-tidy | 13 +++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 .markdownlint.yaml create mode 100644 tools/beman-tidy/README.md create mode 100755 tools/beman-tidy/beman-tidy diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..81f5fcd7 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,9 @@ +# MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md033.md +# Disable inline html linter is needed for
+MD033: false + +# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md013.md +# Conforms to .clang-format ColumnLimit +# Update the comment in .clang-format if we no-longer tie these two column limits. +MD013: + line_length: 119 diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md new file mode 100644 index 00000000..0dc61d60 --- /dev/null +++ b/tools/beman-tidy/README.md @@ -0,0 +1,22 @@ +# beman-tidy: Codebase Beminification Tool + + + +## Description +TODO: Add a description. + +## Installation +TODO: Add an installation section. + +## Usage +TODO: Add a usage section. + +```shell +$ ./tools/beman-tidy/beman-tidy --help +beman-tidy is a tool to check the coding standard of The Beman Project. + +$ ./tools/beman-tidy/beman-tidy +beman-tidy is a tool to check the coding standard of The Beman Project. +``` diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy new file mode 100755 index 00000000..7d5f8eeb --- /dev/null +++ b/tools/beman-tidy/beman-tidy @@ -0,0 +1,13 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +def main(): + """ + beman-tidy is a tool to check the coding standard of The Beman Project. + Check https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md. + """ + print("beman-tidy is a tool to check the coding standard of The Beman Project.") + pass + +if __name__ == "__main__": + main() From f262e1fa81ddc4db86ef38403e83641b818ca19f Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 22 Jan 2025 11:43:15 +0200 Subject: [PATCH 030/371] beman-tidy: add checks pipeline --- README.md | 3 +- tools/beman-tidy/README.md | 43 +++++++- tools/beman-tidy/beman-tidy | 32 +++++- .../beman-tidy/utils/beman_standard_checks.py | 101 ++++++++++++++++++ tools/beman-tidy/utils/checks_pipeline.py | 44 ++++++++ tools/beman-tidy/utils/git.py | 59 ++++++++++ tools/beman-tidy/utils/run.py | 16 +++ 7 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 tools/beman-tidy/utils/beman_standard_checks.py create mode 100644 tools/beman-tidy/utils/checks_pipeline.py create mode 100644 tools/beman-tidy/utils/git.py create mode 100644 tools/beman-tidy/utils/run.py diff --git a/README.md b/README.md index dae43132..8ea7b618 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ SPDX-License-Identifier: 2.0 license with LLVM exceptions --> -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. +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. ## Description diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 0dc61d60..92e75007 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -5,18 +5,59 @@ SPDX-License-Identifier: 2.0 license with LLVM exceptions --> ## Description + TODO: Add a 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). + ## Installation + TODO: Add an installation section. ## Usage + TODO: Add a usage section. ```shell $ ./tools/beman-tidy/beman-tidy --help -beman-tidy is a tool to check the coding standard of The Beman Project. +usage: beman-tidy [-h] --repo_path REPO_PATH [--fix | --no-fix] + +optional arguments: + -h, --help show this help message and exit + --repo_path REPO_PATH + path to the repository to check + --fix, --no-fix try to automatically fix found issues (default: False) + +# no errors found example +$ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar +Checks pipeline started ... + +Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... + check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... PASSED +... + +Checks pipeline completed. +# errors found example +$ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar +Checks pipeline started ... + +Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... + check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... FAILED + +... + +Checks pipeline completed. + +# errors found + --fix example $ ./tools/beman-tidy/beman-tidy beman-tidy is a tool to check the coding standard of The Beman Project. + +/tools/beman-tidy/beman-tidy --repo_path ../exemplar --fix +Checks pipeline started ... + +Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... + check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... FAILED + +[ERROR ][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES]: The fix cannot be applied inplace. Please commit or stash your changes. STOP. ``` diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 7d5f8eeb..deb1227b 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -1,13 +1,37 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions +import argparse +from utils.git import get_repo_info +from utils.checks_pipeline import run_checks_pipeline + +def parse_args(): + """ + Parse the command line arguments. + """ + + parser = argparse.ArgumentParser() + parser.add_argument("--repo_path", help="path to the repository to check", + required=True) + parser.add_argument("--fix", help="try to automatically fix found issues", + action=argparse.BooleanOptionalAction, default=False) + args = parser.parse_args() + + # Get repository information + repo_info = get_repo_info(args.repo_path) + args.prepo_pathath = None + args.repo_info = repo_info + + return args + + def main(): """ - beman-tidy is a tool to check the coding standard of The Beman Project. - Check https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md. + beman-tidy main entry point. """ - print("beman-tidy is a tool to check the coding standard of The Beman Project.") - pass + args = parse_args() + + run_checks_pipeline(args.fix, args.repo_info) if __name__ == "__main__": main() diff --git a/tools/beman-tidy/utils/beman_standard_checks.py b/tools/beman-tidy/utils/beman_standard_checks.py new file mode 100644 index 00000000..c6d98955 --- /dev/null +++ b/tools/beman-tidy/utils/beman_standard_checks.py @@ -0,0 +1,101 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +import os +import sys + + +class BSCheck(object): + """ + Base class for all Beman Standard checks. + """ + + def __init__(self, repo_info, check_type, check_name): + """ + Initialize the check. + """ + self.name = check_name + # TODO: Automatically pull BEMAN_STANDARD.md and check if the check_name is in the list. + self.type = check_type + assert self.type in ['REQUIREMENT', 'RECOMMANDATION'] + + # TODO: Automatically pull BEMAN_STANDARD.md and populated descrittion + # self.description = ... + + self.log_level = 'ERROR' if check_type == 'REQUIREMENT' else 'WARNING' + self.log_enabled = True + + # TODO + self.repo_info = repo_info + # Shortcuts for repo info + self.repo_name = repo_info["name"] + self.repo_path = repo_info["top_level"] + self.top_level_cmakelists_path = os.path.join( + self.repo_path, 'CMakeLists.txt') + + def check(self, log_enabled=True): + """ + Checks if the Beman Standard check/rule is already applied. + - If the standard is applied, the check should return True. + - If the standard is not applied, the check should return False and self.fix() should be able to fix the issue. + + Base check method that should be overridden by subclasses. + But it should be called directly on first line of the subclass check method. + """ + self.log_enabled = log_enabled + + if self.name is None: + self.log("The name is not set.") + return False + + if self.repo_name is None: + self.log(f"The repo_name is not set for check = {self.name}.") + return False + + if self.repo_path is None: + self.log(f"The repo_path is not set for check = {self.name}.") + return False + + return True + + def fix(self): + """ + Fixes the issue if The Beman Standard is not applied. + - If the standard is applied, the check should return True. NOP here. + - - Otherwise, the check should be applied inplace. If the check cannot be applied inplace, the check should return False. + """ + return False + + def log(self, message, enabled=True): + """ + 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.' + """ + + if enabled: + print(f'[{self.log_level:<15}][{self.name:<25}]: {message}') + + +class BSCheckFixInplaceIncompatibleWithUnstagedChanges(BSCheck): + """ + Check if the fix can be applied inplace. + """ + + def __init__(self, repo_info): + super().__init__(repo_info, 'REQUIREMENT', + 'FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES') + + def check(self): + """ + Check already applied if no unstaged changes are present. + """ + return super().check() and len(self.repo_info["unstaged_changes"]) == 0 + + def fix(self): + """ + Fix the issue if the fix can be applied inplace, so unstaged changes are not present! + """ + self.log( + "The fix cannot be applied inplace. Please commit or stash your changes. STOP.") + sys.exit(1) diff --git a/tools/beman-tidy/utils/checks_pipeline.py b/tools/beman-tidy/utils/checks_pipeline.py new file mode 100644 index 00000000..c2a95833 --- /dev/null +++ b/tools/beman-tidy/utils/checks_pipeline.py @@ -0,0 +1,44 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from .beman_standard_checks import * + + +def get_checks_pipeline(repo_info): + """ + Get the checks pipeline for The Beman Standard. + Returns a list of checks that need to be run. + """ + return [ + # Validate CLI arguments + BSCheckFixInplaceIncompatibleWithUnstagedChanges, + + # Validate ... + ] + + +def run_checks_pipeline(fix_inplace, repo_info): + """ + Run the checks pipeline for The Beman Standard. + If fix_inplace is True, fix the issues inplace. + """ + + print("Checks pipeline started ...\n") + checks_pipeline = get_checks_pipeline(repo_info) + for bs_check_type in checks_pipeline: + bs_check = bs_check_type(repo_info) + print( + f"Running check [{bs_check.type}][{bs_check.name}] ... ") + + if bs_check.check(): + print(f"\tcheck [{bs_check.type}][{bs_check.name}] ... PASSED\n") + else: + print(f"\tcheck [{bs_check.type}][{bs_check.name}] ... FAILED\n") + + if fix_inplace: + if bs_check.fix(): + bs_check.log(f"\tcheck '{bs_check.name}' ... FIXED.") + else: + bs_check.log( + f"\tcheck '{bs_check.name}' ... FAILED TO FIX INPLACE. Please manually fix it!") + print("\nChecks pipeline completed.") diff --git a/tools/beman-tidy/utils/git.py b/tools/beman-tidy/utils/git.py new file mode 100644 index 00000000..2500468d --- /dev/null +++ b/tools/beman-tidy/utils/git.py @@ -0,0 +1,59 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from .run import run_command +import os +import sys + +from git import Repo, InvalidGitRepositoryError + + +def get_repo_info(path): + """ + Get information about the Git repository at the given path. + Returns a dictionary with data about the repository. + """ + + try: + # Initialize the repository object + repo = Repo(os.path.abspath(path), search_parent_directories=True) + + # Get the top-level directory of the repository + top_level_dir = repo.git.rev_parse("--show-toplevel") + + # Get the repository name (directory name of the top level) + repo_name = os.path.basename(top_level_dir) + + # Get the remote URL (assuming 'origin' is the remote name) + remote_url = None + if "origin" in repo.remotes: + remote_url = repo.remotes.origin.url + + # Get the current branch + current_branch = repo.active_branch.name + + # Get the commit hash + commit_hash = repo.head.commit.hexsha + + # Get the status of the repository + status = repo.git.status() + + # Get unstaged changes + unstaged_changes = repo.git.diff("--stat") + + return { + "top_level": top_level_dir, + "name": repo_name, + "remote_url": remote_url, + "current_branch": current_branch, + "commit_hash": commit_hash, + "status": status, + "unstaged_changes": unstaged_changes, + } + except InvalidGitRepositoryError: + print(f"The path '{path}' is not inside a valid Git repository.") + sys.exit(1) + except Exception as e: + print( + f"An error occurred while getting repository information. Check {path}.") + sys.exit(1) diff --git a/tools/beman-tidy/utils/run.py b/tools/beman-tidy/utils/run.py new file mode 100644 index 00000000..4643fbc3 --- /dev/null +++ b/tools/beman-tidy/utils/run.py @@ -0,0 +1,16 @@ +import subprocess + + +def run_command(command, return_stdout=False, cwd=None): + """ + Run a command in the shell and return the return code. + If return_stdout is True, return the stdout of the command. + Optionally, change the current working directory to cwd. + """ + print(f"Running command: {command} with cwd: {cwd}") + if return_stdout: + bin = subprocess.Popen(command, shell=True, + stdout=subprocess.PIPE, cwd=cwd).stdout.read() + return bin.decode("ascii") + else: + return subprocess.run(command, shell=True, cwd=cwd).returncode From c6541beb430a166ebce680c7754f9bacfc1355f2 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 22 Jan 2025 14:12:16 +0200 Subject: [PATCH 031/371] beman-tidy: add coverage stats --- tools/beman-tidy/README.md | 20 +++++-- tools/beman-tidy/beman-tidy | 9 ++- .../beman-tidy/utils/beman_standard_checks.py | 30 ++++++---- tools/beman-tidy/utils/checks_pipeline.py | 48 ++++++++++++++-- tools/beman-tidy/utils/git.py | 56 +++++++++++++++++++ tools/beman-tidy/utils/run.py | 2 +- 6 files changed, 141 insertions(+), 24 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 92e75007..7ec9853b 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -20,13 +20,13 @@ TODO: Add a usage section. ```shell $ ./tools/beman-tidy/beman-tidy --help -usage: beman-tidy [-h] --repo_path REPO_PATH [--fix | --no-fix] - -optional arguments: -h, --help show this help message and exit --repo_path REPO_PATH path to the repository to check - --fix, --no-fix try to automatically fix found issues (default: False) + --fix_inplace, --no-fix_inplace + try to automatically fix found issues (default: False) + --coverage, --no-coverage + show coverage of the checks (default: False) # no errors found example $ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar @@ -60,4 +60,16 @@ Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... FAILED [ERROR ][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES]: The fix cannot be applied inplace. Please commit or stash your changes. STOP. + +# coverage example +$ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar --coverage +Checks pipeline started ... + +Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... + check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... PASSED + + +Checks pipeline completed. +repo coverage over The Beman Standard: 0.0% (0/43 checks passed). +clang-tidy coverage over The Beman Standard: 0.0% (0/43 checks implemented). ``` diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index deb1227b..c45f87ea 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,7 +2,7 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions import argparse -from utils.git import get_repo_info +from utils.git import get_repo_info, download_beman_standard from utils.checks_pipeline import run_checks_pipeline def parse_args(): @@ -13,7 +13,9 @@ def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("--repo_path", help="path to the repository to check", required=True) - parser.add_argument("--fix", help="try to automatically fix found issues", + parser.add_argument("--fix_inplace", help="try to automatically fix found issues", + action=argparse.BooleanOptionalAction, default=False) + parser.add_argument("--coverage", help="show coverage of the checks", action=argparse.BooleanOptionalAction, default=False) args = parser.parse_args() @@ -31,7 +33,8 @@ def main(): """ args = parse_args() - run_checks_pipeline(args.fix, args.repo_info) + beman_standard = download_beman_standard() + run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace, coverage=args.coverage) if __name__ == "__main__": main() diff --git a/tools/beman-tidy/utils/beman_standard_checks.py b/tools/beman-tidy/utils/beman_standard_checks.py index c6d98955..8e562a84 100644 --- a/tools/beman-tidy/utils/beman_standard_checks.py +++ b/tools/beman-tidy/utils/beman_standard_checks.py @@ -10,22 +10,32 @@ class BSCheck(object): Base class for all Beman Standard checks. """ - def __init__(self, repo_info, check_type, check_name): + def __init__(self, repo_info, beman_standard, check_name): """ Initialize the check. """ + # check name e.g. "LIBRARY.NAMES" self.name = check_name - # TODO: Automatically pull BEMAN_STANDARD.md and check if the check_name is in the list. - self.type = check_type - assert self.type in ['REQUIREMENT', 'RECOMMANDATION'] - # TODO: Automatically pull BEMAN_STANDARD.md and populated descrittion - # self.description = ... + # unique entry in the list - [(check_name, check_type, check_full_text_body)] + beman_standard_check = [ + entry for entry in beman_standard if entry[0] == check_name] + assert len(beman_standard_check) <= 1 + + # set type and full_text_body + if len(beman_standard_check) == 1: + (check_name, check_type, check_body) = beman_standard_check[0] + + self.type = check_type + self.full_text_body = check_body + else: + self.type = "REQUIREMENT" + self.full_text_body = "beman-tidy internal check." + assert self.type in ['REQUIREMENT', 'RECOMMANDATION'] - self.log_level = 'ERROR' if check_type == 'REQUIREMENT' else 'WARNING' + self.log_level = 'ERROR' if self.type == 'REQUIREMENT' else 'WARNING' self.log_enabled = True - # TODO self.repo_info = repo_info # Shortcuts for repo info self.repo_name = repo_info["name"] @@ -82,8 +92,8 @@ class BSCheckFixInplaceIncompatibleWithUnstagedChanges(BSCheck): Check if the fix can be applied inplace. """ - def __init__(self, repo_info): - super().__init__(repo_info, 'REQUIREMENT', + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, 'FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES') def check(self): diff --git a/tools/beman-tidy/utils/checks_pipeline.py b/tools/beman-tidy/utils/checks_pipeline.py index c2a95833..0076f0f5 100644 --- a/tools/beman-tidy/utils/checks_pipeline.py +++ b/tools/beman-tidy/utils/checks_pipeline.py @@ -4,9 +4,11 @@ from .beman_standard_checks import * -def get_checks_pipeline(repo_info): +def get_all_implemented_checks(): """ - Get the checks pipeline for The Beman Standard. + Get the checks pipeline - it is a list of checks, that need to be run. + The list may contain checks that are not from The Beman Standard. + Returns a list of checks that need to be run. """ return [ @@ -17,16 +19,23 @@ def get_checks_pipeline(repo_info): ] -def run_checks_pipeline(fix_inplace, repo_info): +def get_beman_standard_check(beman_standard, check_name): + """ + Get The Beman Standard check object from the Beman Standard that matches the check_name. + """ + return next(filter(lambda bs_check: bs_check[0] == check_name, beman_standard), None) + + +def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, coverage=False): """ Run the checks pipeline for The Beman Standard. If fix_inplace is True, fix the issues inplace. + If coverage is True, print the coverage. """ print("Checks pipeline started ...\n") - checks_pipeline = get_checks_pipeline(repo_info) - for bs_check_type in checks_pipeline: - bs_check = bs_check_type(repo_info) + for generic_check in get_all_implemented_checks(): + bs_check = generic_check(repo_info, beman_standard) print( f"Running check [{bs_check.type}][{bs_check.name}] ... ") @@ -41,4 +50,31 @@ def run_checks_pipeline(fix_inplace, repo_info): else: bs_check.log( f"\tcheck '{bs_check.name}' ... FAILED TO FIX INPLACE. Please manually fix it!") + print("\nChecks pipeline completed.") + + if coverage: + print_coverage(repo_info, beman_standard) + + +def print_coverage(repo_info, beman_standard): + """ + Print The Beman Standard coverage. + """ + # Actual implemented checks. + all_implemented_checks = [generic_check( + repo_info, beman_standard) for generic_check in get_all_implemented_checks()] + bs_implemented_checks = [generic_check for generic_check in all_implemented_checks if get_beman_standard_check( + beman_standard, generic_check.name)] + passed_bs_checks = [ + bs_check for bs_check in bs_implemented_checks if bs_check.check()] + + # Stats about the clang-tidy checks coverage over The Beman Standard. + total_bs_hecks = len(beman_standard) + total_implemented_bs_checks = len([generic_check for generic_check in get_all_implemented_checks( + ) if get_beman_standard_check(beman_standard, generic_check(repo_info, beman_standard))]) + + print( + f"repo coverage over The Beman Standard: {len(passed_bs_checks) / total_bs_hecks * 100}% ({len(passed_bs_checks)}/{total_bs_hecks} checks passed).") + print( + f"clang-tidy coverage over The Beman Standard: {total_implemented_bs_checks / total_bs_hecks * 100}% ({total_implemented_bs_checks}/{total_bs_hecks} checks implemented).") diff --git a/tools/beman-tidy/utils/git.py b/tools/beman-tidy/utils/git.py index 2500468d..ebe0571b 100644 --- a/tools/beman-tidy/utils/git.py +++ b/tools/beman-tidy/utils/git.py @@ -2,7 +2,10 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions from .run import run_command +import markdown import os +import re +import requests import sys from git import Repo, InvalidGitRepositoryError @@ -57,3 +60,56 @@ def get_repo_info(path): print( f"An error occurred while getting repository information. Check {path}.") sys.exit(1) + + +def parse_beman_standard(beman_standard_md_content): + """ + Parse the Markdown content to extract checks from The Beman Standard + + Args: + markdown_content (str): The raw Markdown content. + + Returns: + [(check_name, check_type, check_body)]: A list of check tuples. + """ + # Regex pattern to match checks + pattern = r"\*\*\[([A-Z._]+)\]\*\* (REQUIREMENT|RECOMMENDATION):\s*(.*?)(?=\*\*\[|$)" + matches = re.finditer(pattern, beman_standard_md_content, re.DOTALL) + + bs_checks = [] + for match in matches: + check_name = match.group(1) + check_type = match.group(2) + check_body = match.group(3).strip() + + bs_checks.append((check_name, check_type, check_body)) + + return bs_checks + + +def download_beman_standard(): + """ + Download and parse The Beman Standard content from the GitHub repository. + + Returns: + str: Rendered Markdown content as a string. + """ + # Raw GitHub URL for the Markdown file + raw_url = "https://raw.githubusercontent.com/bemanproject/beman/main/docs/BEMAN_STANDARD.md" + + try: + # Fetch the content + response = requests.get(raw_url) + response.raise_for_status() # Raise an exception for HTTP errors + + # Get the Markdown content + beman_standard_md_content = response.text + + # Get the actual checks + bs_checks = parse_beman_standard(beman_standard_md_content) + + return bs_checks + except requests.RequestException as e: + print( + f"An error occurred while The Beman Standard from ${raw_url}: {e}.\nSTOP.") + sys.exit(1) diff --git a/tools/beman-tidy/utils/run.py b/tools/beman-tidy/utils/run.py index 4643fbc3..5e5d6ef6 100644 --- a/tools/beman-tidy/utils/run.py +++ b/tools/beman-tidy/utils/run.py @@ -11,6 +11,6 @@ def run_command(command, return_stdout=False, cwd=None): if return_stdout: bin = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, cwd=cwd).stdout.read() - return bin.decode("ascii") + return bin.decode("utf-8") else: return subprocess.run(command, shell=True, cwd=cwd).returncode From 36841441b7e6c3560bcd1838260311d7d571ae55 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 22 Jan 2025 14:51:52 +0200 Subject: [PATCH 032/371] beman-tidy: add skel for all Beman Standard checks --- tools/beman-tidy/__init__.py | 0 tools/beman-tidy/beman-tidy | 4 +- tools/beman-tidy/lib/__init__.py | 0 tools/beman-tidy/lib/checks/__init__.py | 0 .../lib/checks/abstract/__init__.py | 0 .../checks/abstract/generic_check.py} | 44 ++++++------------- .../lib/checks/beman_standard/__init__.py | 0 .../lib/checks/beman_standard/changelog.py | 8 ++++ .../lib/checks/beman_standard/cmake.py | 17 +++++++ .../lib/checks/beman_standard/cpp.py | 8 ++++ .../lib/checks/beman_standard/directory.py | 13 ++++++ .../lib/checks/beman_standard/file.py | 10 +++++ .../lib/checks/beman_standard/general.py | 8 ++++ .../lib/checks/beman_standard/licence.py | 9 ++++ .../lib/checks/beman_standard/readme.py | 10 +++++ .../lib/checks/beman_standard/toplevel.py | 7 +++ .../beman-tidy/lib/checks/system/__init__.py | 0 tools/beman-tidy/lib/checks/system/git.py | 30 +++++++++++++ .../checks_pipeline.py => lib/pipeline.py} | 4 +- tools/beman-tidy/{ => lib}/utils/git.py | 2 +- tools/beman-tidy/lib/utils/string.py | 13 ++++++ .../{utils/run.py => lib/utils/terminal.py} | 4 +- 22 files changed, 154 insertions(+), 37 deletions(-) create mode 100644 tools/beman-tidy/__init__.py create mode 100644 tools/beman-tidy/lib/__init__.py create mode 100644 tools/beman-tidy/lib/checks/__init__.py create mode 100644 tools/beman-tidy/lib/checks/abstract/__init__.py rename tools/beman-tidy/{utils/beman_standard_checks.py => lib/checks/abstract/generic_check.py} (80%) create mode 100644 tools/beman-tidy/lib/checks/beman_standard/__init__.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/changelog.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/cmake.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/cpp.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/directory.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/file.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/general.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/licence.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/readme.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/toplevel.py create mode 100644 tools/beman-tidy/lib/checks/system/__init__.py create mode 100644 tools/beman-tidy/lib/checks/system/git.py rename tools/beman-tidy/{utils/checks_pipeline.py => lib/pipeline.py} (97%) rename tools/beman-tidy/{ => lib}/utils/git.py (99%) create mode 100644 tools/beman-tidy/lib/utils/string.py rename tools/beman-tidy/{utils/run.py => lib/utils/terminal.py} (88%) diff --git a/tools/beman-tidy/__init__.py b/tools/beman-tidy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index c45f87ea..f5f326cf 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,8 +2,8 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions import argparse -from utils.git import get_repo_info, download_beman_standard -from utils.checks_pipeline import run_checks_pipeline +from lib.utils.git import get_repo_info, download_beman_standard +from lib.pipeline import run_checks_pipeline def parse_args(): """ diff --git a/tools/beman-tidy/lib/__init__.py b/tools/beman-tidy/lib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/lib/checks/__init__.py b/tools/beman-tidy/lib/checks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/lib/checks/abstract/__init__.py b/tools/beman-tidy/lib/checks/abstract/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/utils/beman_standard_checks.py b/tools/beman-tidy/lib/checks/abstract/generic_check.py similarity index 80% rename from tools/beman-tidy/utils/beman_standard_checks.py rename to tools/beman-tidy/lib/checks/abstract/generic_check.py index 8e562a84..2d6eeccd 100644 --- a/tools/beman-tidy/utils/beman_standard_checks.py +++ b/tools/beman-tidy/lib/checks/abstract/generic_check.py @@ -43,14 +43,9 @@ def __init__(self, repo_info, beman_standard, check_name): self.top_level_cmakelists_path = os.path.join( self.repo_path, 'CMakeLists.txt') - def check(self, log_enabled=True): + def base_check(self, log_enabled=True): """ - Checks if the Beman Standard check/rule is already applied. - - If the standard is applied, the check should return True. - - If the standard is not applied, the check should return False and self.fix() should be able to fix the issue. - - Base check method that should be overridden by subclasses. - But it should be called directly on first line of the subclass check method. + Checks if this rule is properly initialized. """ self.log_enabled = log_enabled @@ -68,6 +63,17 @@ def check(self, log_enabled=True): return True + def check(self, log_enabled=True): + """ + Checks if the Beman Standard check/rule is already applied. + - If the standard is applied, the check should return True. + - If the standard is not applied, the check should return False and self.fix() should be able to fix the issue. + + Base check method that should be overridden by subclasses. + But it should be called directly on first line of the subclass check method. + """ + return self.base_check(log_enabled) + def fix(self): """ Fixes the issue if The Beman Standard is not applied. @@ -85,27 +91,3 @@ def log(self, message, enabled=True): if enabled: print(f'[{self.log_level:<15}][{self.name:<25}]: {message}') - - -class BSCheckFixInplaceIncompatibleWithUnstagedChanges(BSCheck): - """ - Check if the fix can be applied inplace. - """ - - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, - 'FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES') - - def check(self): - """ - Check already applied if no unstaged changes are present. - """ - return super().check() and len(self.repo_info["unstaged_changes"]) == 0 - - def fix(self): - """ - Fix the issue if the fix can be applied inplace, so unstaged changes are not present! - """ - self.log( - "The fix cannot be applied inplace. Please commit or stash your changes. STOP.") - sys.exit(1) diff --git a/tools/beman-tidy/lib/checks/beman_standard/__init__.py b/tools/beman-tidy/lib/checks/beman_standard/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/lib/checks/beman_standard/changelog.py b/tools/beman-tidy/lib/checks/beman_standard/changelog.py new file mode 100644 index 00000000..d3eb6d73 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/changelog.py @@ -0,0 +1,8 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO CHANGELOG.TITLE +# TODO CHANGELOG.FORMAT diff --git a/tools/beman-tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/lib/checks/beman_standard/cmake.py new file mode 100644 index 00000000..25c8161a --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/cmake.py @@ -0,0 +1,17 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO CMAKE.DEFAULT +# TODO CMAKE.USE_FETCH_CONTENT +# TODO CMAKE.PROJECT_NAME +# TODO CMAKE.PASSIVE_PROJECTS +# TODO CMAKE.LIBRARY_NAME +# TODO CMAKE.LIBRARY_ALIAS +# TODO CMAKE.TARGET_NAMES +# TODO CMAKE.PASSIVE_TARGETS +# TODO CMAKE.SKIP_TESTS +# TODO CMAKE.SKIP_EXAMPLES +# TODO CMAKE.AVOID_PASSTHROUGHS diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/lib/checks/beman_standard/cpp.py new file mode 100644 index 00000000..03b4aea7 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/cpp.py @@ -0,0 +1,8 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO CPP.NAMESPACE +# TODO CPP.NO_FLAG_FORKING diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/lib/checks/beman_standard/directory.py new file mode 100644 index 00000000..94d6dd39 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/directory.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO DIRECTORY.INTERFACE_HEADERS +# TODO DIRECTORY.IMPLEMENTATION_HEADERS +# TODO DIRECTORY.SOURCES +# TODO DIRECTORY.TESTS +# TODO DIRECTORY.EXAMPLES +# TODO DIRECTORY.DOCS +# TODO DIRECTORY.PAPERS diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/lib/checks/beman_standard/file.py new file mode 100644 index 00000000..e91bb739 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/file.py @@ -0,0 +1,10 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO FILE.NAMES +# TODO FILE.TEST_NAMES +# TODO FILE.LICENSE_ID +# TODO FILE.COPYRIGHT diff --git a/tools/beman-tidy/lib/checks/beman_standard/general.py b/tools/beman-tidy/lib/checks/beman_standard/general.py new file mode 100644 index 00000000..30d9f373 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/general.py @@ -0,0 +1,8 @@ + +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +# TODO LIBRARY.NAMES +# TODO REPOSITORY.NAME +# TODO REPOSITORY.CODEOWNERS +# TODO REPOSITORY.DISALLOW_GIT_SUBMODULES diff --git a/tools/beman-tidy/lib/checks/beman_standard/licence.py b/tools/beman-tidy/lib/checks/beman_standard/licence.py new file mode 100644 index 00000000..9bde5485 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/licence.py @@ -0,0 +1,9 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO LICENSE.APPROVED +# TODO LICENSE.APACHE_LLVM +# TODO LICENSE.CRITERIA diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py new file mode 100644 index 00000000..2c1376a4 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -0,0 +1,10 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + + +# TODO README.TITLE +# TODO README.PURPOSE +# TODO README.IMPLEMENTS +# TODO README.LIBRARY_STATUS diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py new file mode 100644 index 00000000..1c22a699 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +# TODO TOPLEVEL.CHANGELOG +# TODO TOPLEVEL.CMAKE +# TODO TOPLEVEL.LICENSE +# TODO TOPLEVEL.README diff --git a/tools/beman-tidy/lib/checks/system/__init__.py b/tools/beman-tidy/lib/checks/system/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py new file mode 100644 index 00000000..a55e9538 --- /dev/null +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -0,0 +1,30 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from ..abstract.generic_check import BSCheck + +import sys + + +class BSCheckFixInplaceIncompatibleWithUnstagedChanges(BSCheck): + """ + Check if the fix can be applied inplace. + """ + + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, + 'FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES') + + def check(self): + """ + Check already applied if no unstaged changes are present. + """ + return len(self.repo_info["unstaged_changes"]) == 0 + + def fix(self): + """ + Fix the issue if the fix can be applied inplace, so unstaged changes are not present! + """ + self.log( + "The fix cannot be applied inplace. Please commit or stash your changes. STOP.") + sys.exit(1) diff --git a/tools/beman-tidy/utils/checks_pipeline.py b/tools/beman-tidy/lib/pipeline.py similarity index 97% rename from tools/beman-tidy/utils/checks_pipeline.py rename to tools/beman-tidy/lib/pipeline.py index 0076f0f5..f775b35e 100644 --- a/tools/beman-tidy/utils/checks_pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from .beman_standard_checks import * +from .checks.system.git import * def get_all_implemented_checks(): @@ -39,7 +39,7 @@ def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, coverage=F print( f"Running check [{bs_check.type}][{bs_check.name}] ... ") - if bs_check.check(): + if bs_check.base_check() and bs_check.check(): print(f"\tcheck [{bs_check.type}][{bs_check.name}] ... PASSED\n") else: print(f"\tcheck [{bs_check.type}][{bs_check.name}] ... FAILED\n") diff --git a/tools/beman-tidy/utils/git.py b/tools/beman-tidy/lib/utils/git.py similarity index 99% rename from tools/beman-tidy/utils/git.py rename to tools/beman-tidy/lib/utils/git.py index ebe0571b..f390388b 100644 --- a/tools/beman-tidy/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from .run import run_command +from .terminal import run_command import markdown import os import re diff --git a/tools/beman-tidy/lib/utils/string.py b/tools/beman-tidy/lib/utils/string.py new file mode 100644 index 00000000..ccfa134e --- /dev/null +++ b/tools/beman-tidy/lib/utils/string.py @@ -0,0 +1,13 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +def is_snake_case(name): + return re.match("(^[a-z0-9]+$)|(^[a-z0-9][a-z0-9_.]+[a-z0-9]$)", name) + +def is_beman_snake_case(name): + """ + Has prefix "beman." and continues with snake_case. + It must NOT end with a C++ target standard version - e.g. 17, 20, 23, 26, 32, etc. + """ + + return name[:6] == "beman." and is_snake_case(name[6:]) and not re.match(".*[0-9]+$", name[6:]) diff --git a/tools/beman-tidy/utils/run.py b/tools/beman-tidy/lib/utils/terminal.py similarity index 88% rename from tools/beman-tidy/utils/run.py rename to tools/beman-tidy/lib/utils/terminal.py index 5e5d6ef6..dd0b7087 100644 --- a/tools/beman-tidy/utils/run.py +++ b/tools/beman-tidy/lib/utils/terminal.py @@ -1,5 +1,7 @@ -import subprocess +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions +import subprocess def run_command(command, return_stdout=False, cwd=None): """ From 7edd2226c55d8d5abd236a98ce649bcf86eba46e Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 22 Jan 2025 15:50:09 +0200 Subject: [PATCH 033/371] beman-tidy: implement checks for TOPLEVEL rules --- tools/beman-tidy/beman-tidy | 1 - .../lib/checks/{abstract => base}/__init__.py | 0 .../generic_check.py => base/base_check.py} | 12 ++- .../lib/checks/base/generic_file_check.py | 75 +++++++++++++++++++ .../lib/checks/beman_standard/changelog.py | 2 +- .../lib/checks/beman_standard/cmake.py | 2 +- .../lib/checks/beman_standard/cpp.py | 2 +- .../lib/checks/beman_standard/directory.py | 2 +- .../lib/checks/beman_standard/file.py | 2 +- .../beman_standard/{licence.py => license.py} | 2 +- .../lib/checks/beman_standard/readme.py | 26 ++++++- .../lib/checks/beman_standard/toplevel.py | 50 ++++++++++++- tools/beman-tidy/lib/checks/system/git.py | 2 +- tools/beman-tidy/lib/pipeline.py | 29 +++++-- tools/beman-tidy/lib/utils/git.py | 45 ++++++----- tools/beman-tidy/lib/utils/string.py | 4 + tools/beman-tidy/lib/utils/terminal.py | 1 + 17 files changed, 215 insertions(+), 42 deletions(-) rename tools/beman-tidy/lib/checks/{abstract => base}/__init__.py (100%) rename tools/beman-tidy/lib/checks/{abstract/generic_check.py => base/base_check.py} (92%) create mode 100644 tools/beman-tidy/lib/checks/base/generic_file_check.py rename tools/beman-tidy/lib/checks/beman_standard/{licence.py => license.py} (77%) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index f5f326cf..9c0003b3 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -21,7 +21,6 @@ def parse_args(): # Get repository information repo_info = get_repo_info(args.repo_path) - args.prepo_pathath = None args.repo_info = repo_info return args diff --git a/tools/beman-tidy/lib/checks/abstract/__init__.py b/tools/beman-tidy/lib/checks/base/__init__.py similarity index 100% rename from tools/beman-tidy/lib/checks/abstract/__init__.py rename to tools/beman-tidy/lib/checks/base/__init__.py diff --git a/tools/beman-tidy/lib/checks/abstract/generic_check.py b/tools/beman-tidy/lib/checks/base/base_check.py similarity index 92% rename from tools/beman-tidy/lib/checks/abstract/generic_check.py rename to tools/beman-tidy/lib/checks/base/base_check.py index 2d6eeccd..bd992782 100644 --- a/tools/beman-tidy/lib/checks/abstract/generic_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -37,11 +37,14 @@ def __init__(self, repo_info, beman_standard, check_name): self.log_enabled = True self.repo_info = repo_info - # Shortcuts for repo info + + assert "name" in repo_info self.repo_name = repo_info["name"] + assert "top_level" in repo_info self.repo_path = repo_info["top_level"] - self.top_level_cmakelists_path = os.path.join( - self.repo_path, 'CMakeLists.txt') + + self.library_name = f"beman.{self.repo_name}" + assert self.library_name is not None def base_check(self, log_enabled=True): """ @@ -72,6 +75,8 @@ def check(self, log_enabled=True): Base check method that should be overridden by subclasses. But it should be called directly on first line of the subclass check method. """ + self.log_enabled = log_enabled + return self.base_check(log_enabled) def fix(self): @@ -80,6 +85,7 @@ def fix(self): - If the standard is applied, the check should return True. NOP here. - - Otherwise, the check should be applied inplace. If the check cannot be applied inplace, the check should return False. """ + self.log_enabled = False return False def log(self, message, enabled=True): diff --git a/tools/beman-tidy/lib/checks/base/generic_file_check.py b/tools/beman-tidy/lib/checks/base/generic_file_check.py new file mode 100644 index 00000000..6aacc56e --- /dev/null +++ b/tools/beman-tidy/lib/checks/base/generic_file_check.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: 2.0 license with LLVM exceptions + +from .base_check import BSCheck +import os +import sys + + +class BSGenericFileCheck(BSCheck): + """ + Base class for all Beman Standard checks. + """ + + def __init__(self, repo_info, beman_standard, check_name, relative_path): + super().__init__(repo_info, beman_standard, check_name) + + self.path = os.path.join(repo_info["top_level"], relative_path) + + def base_check(self, log_enabled=True): + """ + Checks if this rule is properly initialized. + """ + self.log_enabled = log_enabled + + if not super().base_check(log_enabled): + return False + + if self.path is None: + self.log("The path is not set.") + return False + + if not os.path.exists(self.path): + self.log(f"The file '{self.path}' does not exist.") + return False + + if len(self.read_lines()) == 0: + self.log(f"The file '{self.path}' is empty.") + return False + + return True + + def read(self): + """ + Read the file content. + """ + with open(self.path, 'r') as file: + return file.read() + + def read_lines(self): + """ + Read the file content as lines. + """ + with open(self.path, 'r') as file: + return file.readlines() + + def read_lines_strip(self): + """ + Read the file content as lines and strip them. + """ + with open(self.path, 'r') as file: + return [line.strip() for line in file.readlines()] + + def write(self, content): + """ + Write the content to the file. + """ + with open(self.path, 'w') as file: + file.write(content) + + def write_lines(self, lines): + """ + Write the lines to the file. + """ + with open(self.path, 'w') as file: + file.writelines(lines) diff --git a/tools/beman-tidy/lib/checks/beman_standard/changelog.py b/tools/beman-tidy/lib/checks/beman_standard/changelog.py index d3eb6d73..4cfbed9f 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/changelog.py +++ b/tools/beman-tidy/lib/checks/beman_standard/changelog.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck # TODO CHANGELOG.TITLE diff --git a/tools/beman-tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/lib/checks/beman_standard/cmake.py index 25c8161a..2232c576 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cmake.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cmake.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck # TODO CMAKE.DEFAULT diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/lib/checks/beman_standard/cpp.py index 03b4aea7..3d49f711 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cpp.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cpp.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck # TODO CPP.NAMESPACE diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/lib/checks/beman_standard/directory.py index 94d6dd39..61a2522f 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/lib/checks/beman_standard/directory.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck # TODO DIRECTORY.INTERFACE_HEADERS diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/lib/checks/beman_standard/file.py index e91bb739..81968b3f 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/file.py +++ b/tools/beman-tidy/lib/checks/beman_standard/file.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck # TODO FILE.NAMES diff --git a/tools/beman-tidy/lib/checks/beman_standard/licence.py b/tools/beman-tidy/lib/checks/beman_standard/license.py similarity index 77% rename from tools/beman-tidy/lib/checks/beman_standard/licence.py rename to tools/beman-tidy/lib/checks/beman_standard/license.py index 9bde5485..13080ffc 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/licence.py +++ b/tools/beman-tidy/lib/checks/beman_standard/license.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck # TODO LICENSE.APPROVED diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 2c1376a4..49e72078 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -1,10 +1,34 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.generic_file_check import BSGenericFileCheck +class BSGenericReadmeCheck(BSGenericFileCheck): + def __init__(self, repo_info, beman_standard, check_name): + super().__init__(repo_info, beman_standard, check_name, "README.md") + # TODO README.TITLE + + +class BSReadmeTitleCheck(BSGenericReadmeCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "README.TITLE") + + def check(self): + """ + The README.md should begin with a level 1 header with the name of the library optionally followed with a ":" and short description. + """ + content = self.read_lines_strip() + if len(content) == 0: + self.log("The root README.md file is empty.") + return False + + # Match the pattern "# [: ]" + if not first_line[2:].startswith(f"{self.library_name}:"): + return False + + # TODO README.PURPOSE # TODO README.IMPLEMENTS # TODO README.LIBRARY_STATUS diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 1c22a699..a50a60b2 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -1,7 +1,49 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -# TODO TOPLEVEL.CHANGELOG -# TODO TOPLEVEL.CMAKE -# TODO TOPLEVEL.LICENSE -# TODO TOPLEVEL.README +from ..base.generic_file_check import BSGenericFileCheck + + +class BSTopLevelChangelogCheck(BSGenericFileCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "TOPLEVEL.CHANGELOG", "CHANGELOG.md") + + # check() already implemented in the base class. + + def fix(self): + # TODO import from beman_standard. + pass + + +class BSTopLevelCMakeListsCheck(BSGenericFileCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "TOPLEVEL.CMAKE", "CMakeLists.txt") + + # check() already implemented in the base class. + + def fix(self): + # TODO import from beman_standard. + pass + + +class BSTopLevelLicenseCheck(BSGenericFileCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "TOPLEVEL.LICENSE", "LICENSE") + + # check() already implemented in the base class. + + def fix(self): + # TODO import from beman_standard. + self.write(download_beman_default_license()) + pass + + +class BSTopLevelREADMECheck(BSGenericFileCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "TOPLEVEL.README", "README.md") + + # check() already implemented in the base class. + + def fix(self): + # TODO import from beman_standard. + pass diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index a55e9538..55cb6858 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..abstract.generic_check import BSCheck +from ..base.base_check import BSCheck import sys diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index f775b35e..73a4e945 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -2,6 +2,15 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions from .checks.system.git import * +from .checks.beman_standard.changelog import * +from .checks.beman_standard.cmake import * +from .checks.beman_standard.cpp import * +from .checks.beman_standard.directory import * +from .checks.beman_standard.file import * +from .checks.beman_standard.general import * +from .checks.beman_standard.license import * +from .checks.beman_standard.readme import * +from .checks.beman_standard.toplevel import * def get_all_implemented_checks(): @@ -15,7 +24,11 @@ def get_all_implemented_checks(): # Validate CLI arguments BSCheckFixInplaceIncompatibleWithUnstagedChanges, - # Validate ... + # TOPLEVEL + BSTopLevelChangelogCheck, + BSTopLevelCMakeListsCheck, + BSTopLevelLicenseCheck, + BSTopLevelREADMECheck, ] @@ -52,6 +65,7 @@ def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, coverage=F f"\tcheck '{bs_check.name}' ... FAILED TO FIX INPLACE. Please manually fix it!") print("\nChecks pipeline completed.") + sys.stdout.flush() if coverage: print_coverage(repo_info, beman_standard) @@ -64,17 +78,16 @@ def print_coverage(repo_info, beman_standard): # Actual implemented checks. all_implemented_checks = [generic_check( repo_info, beman_standard) for generic_check in get_all_implemented_checks()] - bs_implemented_checks = [generic_check for generic_check in all_implemented_checks if get_beman_standard_check( + all_bs_implemented_checks = [generic_check for generic_check in all_implemented_checks if get_beman_standard_check( beman_standard, generic_check.name)] passed_bs_checks = [ - bs_check for bs_check in bs_implemented_checks if bs_check.check()] + bs_check for bs_check in all_bs_implemented_checks if bs_check.check(log_enabled=False)] # Stats about the clang-tidy checks coverage over The Beman Standard. - total_bs_hecks = len(beman_standard) - total_implemented_bs_checks = len([generic_check for generic_check in get_all_implemented_checks( - ) if get_beman_standard_check(beman_standard, generic_check(repo_info, beman_standard))]) + total_bs_checks = len(beman_standard) + total_implemented_bs_checks = len(all_bs_implemented_checks) print( - f"repo coverage over The Beman Standard: {len(passed_bs_checks) / total_bs_hecks * 100}% ({len(passed_bs_checks)}/{total_bs_hecks} checks passed).") + f"repo coverage over The Beman Standard: {len(passed_bs_checks) / total_bs_checks * 100}% ({len(passed_bs_checks)}/{total_bs_checks} checks passed).") print( - f"clang-tidy coverage over The Beman Standard: {total_implemented_bs_checks / total_bs_hecks * 100}% ({total_implemented_bs_checks}/{total_bs_hecks} checks implemented).") + f"clang-tidy coverage over The Beman Standard: {total_implemented_bs_checks / total_bs_checks * 100}% ({total_implemented_bs_checks}/{total_bs_checks} checks implemented).") diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index f390388b..7e57c250 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -87,29 +87,38 @@ def parse_beman_standard(beman_standard_md_content): return bs_checks -def download_beman_standard(): +def download_file(url): """ - Download and parse The Beman Standard content from the GitHub repository. - - Returns: - str: Rendered Markdown content as a string. + Download a file from the given URL. """ - # Raw GitHub URL for the Markdown file - raw_url = "https://raw.githubusercontent.com/bemanproject/beman/main/docs/BEMAN_STANDARD.md" - try: # Fetch the content - response = requests.get(raw_url) + response = requests.get(url) response.raise_for_status() # Raise an exception for HTTP errors - - # Get the Markdown content - beman_standard_md_content = response.text - - # Get the actual checks - bs_checks = parse_beman_standard(beman_standard_md_content) - - return bs_checks + return response.text except requests.RequestException as e: print( - f"An error occurred while The Beman Standard from ${raw_url}: {e}.\nSTOP.") + f"An error occurred while downloading from ${raw_url}: {e}.\nSTOP.") sys.exit(1) + + +# + +def download_beman_standard(): + """ + Download and parse The Beman Standard content from the GitHub repository. + """ + # Raw GitHub URL for the Markdown file + raw_url = "https://raw.githubusercontent.com/bemanproject/beman/main/docs/BEMAN_STANDARD.md" + beman_standard_md_content = download_file(raw_url) + bs_checks = parse_beman_standard(beman_standard_md_content) + return bs_checks + + +def download_beman_default_license(): + """ + Download and parse the default Beman LICENSE content from the GitHub repository. + """ + raw_url = "https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/LICENSE" + licent_content = download_file(raw_url) + return licent_content diff --git a/tools/beman-tidy/lib/utils/string.py b/tools/beman-tidy/lib/utils/string.py index ccfa134e..d1d8023b 100644 --- a/tools/beman-tidy/lib/utils/string.py +++ b/tools/beman-tidy/lib/utils/string.py @@ -1,9 +1,13 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions +from .git import download_beman_default_license + + def is_snake_case(name): return re.match("(^[a-z0-9]+$)|(^[a-z0-9][a-z0-9_.]+[a-z0-9]$)", name) + def is_beman_snake_case(name): """ Has prefix "beman." and continues with snake_case. diff --git a/tools/beman-tidy/lib/utils/terminal.py b/tools/beman-tidy/lib/utils/terminal.py index dd0b7087..619bfab6 100644 --- a/tools/beman-tidy/lib/utils/terminal.py +++ b/tools/beman-tidy/lib/utils/terminal.py @@ -3,6 +3,7 @@ import subprocess + def run_command(command, return_stdout=False, cwd=None): """ Run a command in the shell and return the return code. From cad4eb2e0ca0deeda058f3e64b511e0f7f6a1514 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Fri, 7 Feb 2025 03:08:11 +0200 Subject: [PATCH 034/371] Implement rules README.* --- .../beman-tidy/lib/checks/base/base_check.py | 4 +- .../lib/checks/beman_standard/readme.py | 163 +++++++++++++++++- tools/beman-tidy/lib/pipeline.py | 7 + tools/beman-tidy/lib/utils/git.py | 17 +- tools/beman-tidy/lib/utils/string.py | 25 +++ 5 files changed, 203 insertions(+), 13 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index bd992782..e6e5a9bc 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -31,7 +31,9 @@ def __init__(self, repo_info, beman_standard, check_name): else: self.type = "REQUIREMENT" self.full_text_body = "beman-tidy internal check." - assert self.type in ['REQUIREMENT', 'RECOMMANDATION'] + assert self.type in [ + 'REQUIREMENT', 'RECOMMENDATION'], f"Invalid check type: {self.type} for check = {self.name}." + assert self.full_text_body is not None self.log_level = 'ERROR' if self.type == 'REQUIREMENT' else 'WARNING' self.log_enabled = True diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 49e72078..f63f19a5 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -2,14 +2,14 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions from ..base.generic_file_check import BSGenericFileCheck +from ...utils.string import * +from ...utils.git import * class BSGenericReadmeCheck(BSGenericFileCheck): def __init__(self, repo_info, beman_standard, check_name): super().__init__(repo_info, beman_standard, check_name, "README.md") -# TODO README.TITLE - class BSReadmeTitleCheck(BSGenericReadmeCheck): def __init__(self, repo_info, beman_standard): @@ -17,18 +17,163 @@ def __init__(self, repo_info, beman_standard): def check(self): """ - The README.md should begin with a level 1 header with the name of the library optionally followed with a ":" and short description. + The README.md should begin with a level 1 header with the name of the library optionally followed + with a ":" and short description. """ - content = self.read_lines_strip() - if len(content) == 0: - self.log("The root README.md file is empty.") + lines = self.read_lines_strip() + if len(lines) == 0: return False + first_line = lines[0] # Match the pattern "# [: ]" if not first_line[2:].startswith(f"{self.library_name}:"): return False + return True + + +class BSReadmeBadgesCheck(BSGenericReadmeCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "README.BADGES") + + def check(self): + """ + Following the title, the `README.md` must have a one-line badge list: library status (`[README.LIBRARY_STATUS]`), CI status, code coverage. + + Badge format: ![Name with multiple words](url_no_spaces) + Badge line format: ![Name1](url1) ![Name2](url2) ![Name3](url3) ... + + Example: + ![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) + """ + repo_badges = self.parse_lines(self.read_lines_strip()) + if repo_badges is None: + self.log(f"First line of README.md must contain badges.") + return False + + standard_badges = match_badges(self.full_text_body) + if standard_badges is None: + self.log( + f"No badges found in Beman Standard. Please add badge examples to the Beman Standard in section README.BADGES.") + return False + + # Check if the badges in the README.md are the same as in the Beman Standard. + for badge_name, badge_url in repo_badges: + matched_badge = next( + (standard_badge for standard_badge in standard_badges if standard_badge[0] == badge_name), None) + if not matched_badge: + self.log( + f"Badge \"{badge_name}\" not found in the Beman Standard. Standard badges: {set([badge[0] for badge in standard_badges])}.") + return False + beman_standard_badge_url = matched_badge[1] + + if badge_name == "Library Status": + if not badge_url.startswith("https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_"): + self.log( + f"Badge \"{badge_name}\" URL is invalid: {badge_url}. The URL should start with \"https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_\".") + return False + + if badge_url not in [standard_badge[1] for standard_badge in standard_badges]: + self.log( + f"Badge \"{badge_name}\" URL is invalid: {badge_url}. The URL should be in the Beman Standard.") + return False + + if not validate_url(badge_url): + self.log( + f"Badge \"{badge_name}\" URL is invalid: {badge_url}.") + return False + + return True + + def parse_lines(self, lines): + if lines is None or len(lines) == 0: + return None + + lines = skip_lines(lines, 1) # Skip the title. + lines = skip_empty_lines(lines) # Skip empty lines. + # Skip 3 lines of "SPDX-License-Identifier" + lines = skip_lines(lines, 3) + lines = skip_empty_lines(lines) # Skip empty lines. + badge_line = lines[0] if len(lines) > 0 else None + lines = skip_lines(lines, 1) # Skip the badges. + if len(lines) > 0: + # No more badges on remaining lines. + if any(match_badges(line) for line in lines): + self.log(f"Only one line of badges is allowed.") + return None + + return match_badges(badge_line) + +# README.PURPOSE + + +class BSReadmeImplementsCheck(BSGenericReadmeCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "README.IMPLEMENTS") + + def check(self): + """ + Following the purpose and a newline, the README.md should indicate which papers the repository implements. + + Use the following style: + + **Implements**: [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1). + **Implements**: [`std::optional` (P2988R5)](https://wg21.link/P2988R5) and [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1). + """ + lines = self.read_lines_strip() + if len(lines) == 0: + return False + + # Find the line with "Implements", make sure is exactly one. + implements_line = next( + (line for line in lines if line.startswith("**Implements**:")), None) + if not implements_line: + self.log( + f"README.md must contain a line with \"**Implements**: ...\" after the purpose and a newline.") + return False + + # Check if the line is in the correct format. + all_paper_md_links = re.findall( + r"\[.*?\([PD][0-9]*R[0-9]*\)\]\(https://wg21.link/.*?\)", implements_line) + if len(all_paper_md_links) == 0: + self.log( + f"The \"Implements\" line must contain at least one paper link. For example:\n\"**Implements**: [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1)\"") + return False + + return True + + +class BSReadmeLibraryStatusCheck(BSGenericReadmeCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "README.LIBRARY_STATUS") + + def check(self): + """ + Following the implements section and a newline, the README.md must indicate the current library status + with respect to the Beman library maturity model. + """ + lines = self.read_lines_strip() + if len(lines) == 0: + return False + + # Find the line with "Status", make sure is exactly one. + status_line = next( + (line for line in lines if line.startswith("**Status**:")), None) + if not status_line: + self.log( + f"README.md must contain a line with \"**Status**: ...\" after the implements section and a newline.") + return False + + # Check if the line is in the Beman Standard (perfect content match). + beman_standard_status_lines = [line for line in self.full_text_body.split( + "\n") if line.startswith("**Status**:")] + if len(beman_standard_status_lines) == 0: + self.log( + f"The Beman Standard must contain all possible line with format \"**Status**: ...\" in README.LIBRARY_STATUS.") + return False + if status_line not in beman_standard_status_lines: + self.log( + f"Status line \"{status_line}\" not found in the Beman Standard.") + return False -# TODO README.PURPOSE -# TODO README.IMPLEMENTS -# TODO README.LIBRARY_STATUS + return True diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 73a4e945..cc617e54 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -29,6 +29,13 @@ def get_all_implemented_checks(): BSTopLevelCMakeListsCheck, BSTopLevelLicenseCheck, BSTopLevelREADMECheck, + + # README + BSReadmeTitleCheck, + BSReadmeBadgesCheck, + # PURPOSE + BSReadmeImplementsCheck, + BSReadmeLibraryStatusCheck, ] diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 7e57c250..36b75dea 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -102,14 +102,13 @@ def download_file(url): sys.exit(1) -# - def download_beman_standard(): """ Download and parse The Beman Standard content from the GitHub repository. """ # Raw GitHub URL for the Markdown file - raw_url = "https://raw.githubusercontent.com/bemanproject/beman/main/docs/BEMAN_STANDARD.md" + # raw_url = "https://raw.githubusercontent.com/bemanproject/beman/main/docs/BEMAN_STANDARD.md" + raw_url = "https://raw.githubusercontent.com/bemanproject/beman/neatudarius-patch-9/docs/BEMAN_STANDARD.md" beman_standard_md_content = download_file(raw_url) bs_checks = parse_beman_standard(beman_standard_md_content) return bs_checks @@ -122,3 +121,15 @@ def download_beman_default_license(): raw_url = "https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/LICENSE" licent_content = download_file(raw_url) return licent_content + + +def validate_url(url): + """ + Validate the URL. + """ + import requests + try: + response = requests.get(url) + response.raise_for_status() + except requests.RequestException as e: + return False diff --git a/tools/beman-tidy/lib/utils/string.py b/tools/beman-tidy/lib/utils/string.py index d1d8023b..b2772b14 100644 --- a/tools/beman-tidy/lib/utils/string.py +++ b/tools/beman-tidy/lib/utils/string.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions from .git import download_beman_default_license +import re def is_snake_case(name): @@ -15,3 +16,27 @@ def is_beman_snake_case(name): """ return name[:6] == "beman." and is_snake_case(name[6:]) and not re.match(".*[0-9]+$", name[6:]) + + +def match_badges(string): + """ + ![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) + """ + if string is None: + return None + + badges_str = re.findall(r"!\[[^\]]+\]\([^)]+\)", string) + return [re.match(r"!\[([^\]]+)\]\(([^)]+)\)", badge).groups() for badge in badges_str] + + +def skip_lines(lines, n): + return lines[n:] if lines is not None else None + + +def skip_empty_lines(lines): + if lines is None: + return None + + while len(lines) > 0 and len(lines[0].strip()) == 0: + lines = lines[1:] + return lines From 426a31a483d01c70c010f8cb4d3d0f034df23834 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Fri, 7 Feb 2025 03:13:53 +0200 Subject: [PATCH 035/371] Bugfix in validate_url --- tools/beman-tidy/lib/utils/git.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 36b75dea..5c455467 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -131,5 +131,6 @@ def validate_url(url): try: response = requests.get(url) response.raise_for_status() + return True except requests.RequestException as e: return False From 3d0cb43a7a90a87f2fd816323b4f3505f3b5abca Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Fri, 7 Feb 2025 04:03:22 +0200 Subject: [PATCH 036/371] beman-tidy: implement CHANGELOG.* --- .../lib/checks/base/generic_file_check.py | 27 +++-- .../lib/checks/beman_standard/changelog.py | 101 +++++++++++++++++- tools/beman-tidy/lib/pipeline.py | 4 + 3 files changed, 121 insertions(+), 11 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/generic_file_check.py b/tools/beman-tidy/lib/checks/base/generic_file_check.py index 6aacc56e..c585cdeb 100644 --- a/tools/beman-tidy/lib/checks/base/generic_file_check.py +++ b/tools/beman-tidy/lib/checks/base/generic_file_check.py @@ -43,33 +43,40 @@ def read(self): """ Read the file content. """ - with open(self.path, 'r') as file: - return file.read() + try: + with open(self.path, 'r') as file: + return file.read() + except Exception as e: + return "" def read_lines(self): """ Read the file content as lines. """ - with open(self.path, 'r') as file: - return file.readlines() + try: + with open(self.path, 'r') as file: + return file.readlines() + except Exception as e: + return [] def read_lines_strip(self): """ Read the file content as lines and strip them. """ - with open(self.path, 'r') as file: - return [line.strip() for line in file.readlines()] + return [line.strip() for line in self.read_lines()] def write(self, content): """ Write the content to the file. """ - with open(self.path, 'w') as file: - file.write(content) + try: + with open(self.path, 'w') as file: + file.write(content) + except Exception as e: + self.log(f"Error writing the file '{self.path}': {e}") def write_lines(self, lines): """ Write the lines to the file. """ - with open(self.path, 'w') as file: - file.writelines(lines) + self.write("\n".join(lines)) diff --git a/tools/beman-tidy/lib/checks/beman_standard/changelog.py b/tools/beman-tidy/lib/checks/beman_standard/changelog.py index 4cfbed9f..cbf3f45f 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/changelog.py +++ b/tools/beman-tidy/lib/checks/beman_standard/changelog.py @@ -1,8 +1,107 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..base.base_check import BSCheck +from ..base.generic_file_check import BSGenericFileCheck + + +class BSGeneriChangelogCheck(BSGenericFileCheck): + def __init__(self, repo_info, beman_standard, check_name): + super().__init__(repo_info, beman_standard, check_name, "Changelog.md") # TODO CHANGELOG.TITLE +class BSChangelogTitleCheck(BSGeneriChangelogCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "CHANGELOG.TITLE") + + def check(self): + """ + The CHANGELOG.md must begin with a level 1 header with the name "Changelog". + """ + lines = self.read_lines_strip() + if len(lines) == 0: + self.log(f"CHANGELOG.md is empty.") + return False + first_line = lines[0] + + # Match the pattern + if not first_line.startswith("#") or not first_line[2:].startswith("Changelog"): + self.log( + f"CHANGELOG.md must begin with a level 1 header with the name 'Changelog'") + return False + + return True + + def fix(self): + default_line_title = "# Changelog" + + all_lines = self.read_lines_strip() + if len(all_lines) > 0 and all_lines[0].startswith("#"): + all_lines[0] = default_line_title + else: + all_lines.insert(0, default_line_title) + + all_lines.append("") # Add empty line at the end of the file. + self.write_lines(all_lines) + # TODO CHANGELOG.FORMAT + + +class BSChangelogLibraryStatus(BSGeneriChangelogCheck): + def __init__(self, repo_info, beman_standard): + super().__init__(repo_info, beman_standard, "CHANGELOG.LIBRARY_STATUS") + + def check(self): + """ + The CHANGELOG.md must contain a line for each previous library status with respect to the Beman library maturity model. + + The line must be in the format: + - [LIBRARY_STATUS]: Library status updated to [${LIBRARY STATUS}](${LIBRARY STATUS BADGE URL}): It was rejected from ISO standardization. + + """ + all_lines = self.read_lines_strip() + if len(all_lines) == 0: + self.log(f"CHANGELOG.md is empty.") + return False + + # Extract all beman standard library status from the full_text_body. + standard_library_status = [line for line in self.full_text_body.split( + "\n") if line.startswith("- [LIBRARY_STATUS]")] + # Extract all library status from the CHANGELOG.md + changelog_library_status = [ + line for line in all_lines if line.startswith("- [LIBRARY_STATUS]")] + + if len(changelog_library_status) == 0: + self.log(f"CHANGELOG.md must contain a line for each previous library status with respect to the Beman library maturity model. Initial library status is missing.") + return False + + for library_status in changelog_library_status: + # Check for common prefix until 3rd column. + if not any(standard_status[:standard_status.index(")") + 1] in library_status for standard_status in standard_library_status): + self.log( + f"Library status '{library_status}' is not in the correct format.") + return False + + return True + + def fix(self): + # Only if the changelog is empty, add the initial library status. + all_lines = self.read_lines_strip() + if len(all_lines) > 1: + return False + + default_change_log = [ + "# Changelog", + "", + "", + "", + "## [Unreleased]", + "", + "### Added", + "- [LIBRARY_STATUS]: Library status updated to [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): It is not yet ready for production use." + "", + "" + ] + self.write_lines(default_change_log) diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index cc617e54..d965c47e 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -30,6 +30,10 @@ def get_all_implemented_checks(): BSTopLevelLicenseCheck, BSTopLevelREADMECheck, + # CHANGELOG + BSChangelogTitleCheck, + BSChangelogLibraryStatus, + # README BSReadmeTitleCheck, BSReadmeBadgesCheck, From 11d6a010f088813c72b29995ed1d4030865189b3 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 11:02:50 +0100 Subject: [PATCH 037/371] Mirror LICENSE from beman repo --- LICENSE | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/LICENSE b/LICENSE index 537293d6..111a208f 100644 --- a/LICENSE +++ b/LICENSE @@ -216,3 +216,15 @@ 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. From c57d43876f2884eadbe88bef5a73530d27806741 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 11:23:01 +0100 Subject: [PATCH 038/371] Remove unused packages --- tools/beman-tidy/lib/checks/beman_standard/cmake.py | 3 --- tools/beman-tidy/lib/checks/beman_standard/cpp.py | 3 --- tools/beman-tidy/lib/checks/beman_standard/directory.py | 3 --- tools/beman-tidy/lib/checks/beman_standard/file.py | 3 --- tools/beman-tidy/lib/checks/beman_standard/license.py | 3 --- tools/beman-tidy/lib/checks/beman_standard/toplevel.py | 2 +- 6 files changed, 1 insertion(+), 16 deletions(-) diff --git a/tools/beman-tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/lib/checks/beman_standard/cmake.py index 2232c576..faa75763 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cmake.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cmake.py @@ -1,9 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..base.base_check import BSCheck - - # TODO CMAKE.DEFAULT # TODO CMAKE.USE_FETCH_CONTENT # TODO CMAKE.PROJECT_NAME diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/lib/checks/beman_standard/cpp.py index 3d49f711..2f10a19d 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cpp.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cpp.py @@ -1,8 +1,5 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..base.base_check import BSCheck - - # TODO CPP.NAMESPACE # TODO CPP.NO_FLAG_FORKING diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/lib/checks/beman_standard/directory.py index 61a2522f..ed0638db 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/lib/checks/beman_standard/directory.py @@ -1,9 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..base.base_check import BSCheck - - # TODO DIRECTORY.INTERFACE_HEADERS # TODO DIRECTORY.IMPLEMENTATION_HEADERS # TODO DIRECTORY.SOURCES diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/lib/checks/beman_standard/file.py index 81968b3f..366047f1 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/file.py +++ b/tools/beman-tidy/lib/checks/beman_standard/file.py @@ -1,9 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..base.base_check import BSCheck - - # TODO FILE.NAMES # TODO FILE.TEST_NAMES # TODO FILE.LICENSE_ID diff --git a/tools/beman-tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/lib/checks/beman_standard/license.py index 13080ffc..04254596 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/lib/checks/beman_standard/license.py @@ -1,9 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: 2.0 license with LLVM exceptions -from ..base.base_check import BSCheck - - # TODO LICENSE.APPROVED # TODO LICENSE.APACHE_LLVM # TODO LICENSE.CRITERIA diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index a50a60b2..7932f6fb 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions from ..base.generic_file_check import BSGenericFileCheck - +from ...utils.git import * class BSTopLevelChangelogCheck(BSGenericFileCheck): def __init__(self, repo_info, beman_standard): From 9bed1b53bc4155cd2aad78509d274b327487dcb3 Mon Sep 17 00:00:00 2001 From: Chris Hayden Date: Wed, 12 Feb 2025 12:35:29 +0000 Subject: [PATCH 039/371] Initial config-file package creation. --- cmake/beman.exemplar-config.cmake.in | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 cmake/beman.exemplar-config.cmake.in diff --git a/cmake/beman.exemplar-config.cmake.in b/cmake/beman.exemplar-config.cmake.in new file mode 100644 index 00000000..5769cc3b --- /dev/null +++ b/cmake/beman.exemplar-config.cmake.in @@ -0,0 +1,7 @@ +set(BEMAN_EXEMPLAR_VERSION @PROJECT_VERSION@) + +@PACKAGE_INIT@ + +include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake) + +check_required_components(@PROJECT_NAME@) From 374dc72dffba4ffe77e6c20a818289b58e169d63 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 13:52:06 +0100 Subject: [PATCH 040/371] beman-tidy: cleanup for logging --- .../beman-tidy/lib/checks/base/base_check.py | 23 +++++++++---------- .../lib/checks/base/generic_file_check.py | 6 ++--- .../lib/checks/beman_standard/toplevel.py | 13 +++++++---- tools/beman-tidy/lib/pipeline.py | 2 +- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index e6e5a9bc..f8adb758 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -36,7 +36,8 @@ def __init__(self, repo_info, beman_standard, check_name): assert self.full_text_body is not None self.log_level = 'ERROR' if self.type == 'REQUIREMENT' else 'WARNING' - self.log_enabled = True + # log is disabled by default, call set_log_enabled(True) to enable it + self.log_enabled = False self.repo_info = repo_info @@ -48,12 +49,10 @@ def __init__(self, repo_info, beman_standard, check_name): self.library_name = f"beman.{self.repo_name}" assert self.library_name is not None - def base_check(self, log_enabled=True): + def base_check(self): """ Checks if this rule is properly initialized. """ - self.log_enabled = log_enabled - if self.name is None: self.log("The name is not set.") return False @@ -68,18 +67,13 @@ def base_check(self, log_enabled=True): return True - def check(self, log_enabled=True): + def check(self): """ Checks if the Beman Standard check/rule is already applied. - If the standard is applied, the check should return True. - If the standard is not applied, the check should return False and self.fix() should be able to fix the issue. - - Base check method that should be overridden by subclasses. - But it should be called directly on first line of the subclass check method. """ - self.log_enabled = log_enabled - - return self.base_check(log_enabled) + raise NotImplementedError(f"[{self.name}] check() not implemented.") def fix(self): """ @@ -87,7 +81,6 @@ def fix(self): - If the standard is applied, the check should return True. NOP here. - - Otherwise, the check should be applied inplace. If the check cannot be applied inplace, the check should return False. """ - self.log_enabled = False return False def log(self, message, enabled=True): @@ -99,3 +92,9 @@ def log(self, message, enabled=True): if enabled: print(f'[{self.log_level:<15}][{self.name:<25}]: {message}') + + def set_log_enabled(self, log_enabled): + """ + Set the log_enabled flag. + """ + self.log_enabled = log_enabled diff --git a/tools/beman-tidy/lib/checks/base/generic_file_check.py b/tools/beman-tidy/lib/checks/base/generic_file_check.py index c585cdeb..0e831b4c 100644 --- a/tools/beman-tidy/lib/checks/base/generic_file_check.py +++ b/tools/beman-tidy/lib/checks/base/generic_file_check.py @@ -16,13 +16,11 @@ def __init__(self, repo_info, beman_standard, check_name, relative_path): self.path = os.path.join(repo_info["top_level"], relative_path) - def base_check(self, log_enabled=True): + def base_check(self): """ Checks if this rule is properly initialized. """ - self.log_enabled = log_enabled - - if not super().base_check(log_enabled): + if not super().base_check(): return False if self.path is None: diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 7932f6fb..30062a28 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -4,11 +4,13 @@ from ..base.generic_file_check import BSGenericFileCheck from ...utils.git import * + class BSTopLevelChangelogCheck(BSGenericFileCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.CHANGELOG", "CHANGELOG.md") - # check() already implemented in the base class. + def check(self): + return super().base_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. @@ -19,7 +21,8 @@ class BSTopLevelCMakeListsCheck(BSGenericFileCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.CMAKE", "CMakeLists.txt") - # check() already implemented in the base class. + def check(self): + return super().base_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. @@ -30,7 +33,8 @@ class BSTopLevelLicenseCheck(BSGenericFileCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.LICENSE", "LICENSE") - # check() already implemented in the base class. + def check(self): + return super().base_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. @@ -42,7 +46,8 @@ class BSTopLevelREADMECheck(BSGenericFileCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.README", "README.md") - # check() already implemented in the base class. + def check(self): + return super().base_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index d965c47e..002cc589 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -92,7 +92,7 @@ def print_coverage(repo_info, beman_standard): all_bs_implemented_checks = [generic_check for generic_check in all_implemented_checks if get_beman_standard_check( beman_standard, generic_check.name)] passed_bs_checks = [ - bs_check for bs_check in all_bs_implemented_checks if bs_check.check(log_enabled=False)] + bs_check for bs_check in all_bs_implemented_checks if bs_check.base_check() and bs_check.check()] # Stats about the clang-tidy checks coverage over The Beman Standard. total_bs_checks = len(beman_standard) From fa4757a2b509a281eb974799600e9272d4da6e69 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 14:10:25 +0100 Subject: [PATCH 041/371] beman-tidy: improve --coverage displayed text --- tools/beman-tidy/beman-tidy | 26 ++++++++++++++++++-------- tools/beman-tidy/lib/pipeline.py | 25 ++++++++----------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 9c0003b3..89d32382 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,8 +2,8 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions import argparse -from lib.utils.git import get_repo_info, download_beman_standard -from lib.pipeline import run_checks_pipeline +from lib.utils.git import * +from lib.pipeline import * def parse_args(): """ @@ -11,12 +11,12 @@ def parse_args(): """ parser = argparse.ArgumentParser() - parser.add_argument("--repo_path", help="path to the repository to check", - required=True) - parser.add_argument("--fix_inplace", help="try to automatically fix found issues", - action=argparse.BooleanOptionalAction, default=False) + parser.add_argument("--repo-path", help="path to the repository to check", + required=True, type=str) + parser.add_argument("--fix-inplace", help="try to automatically fix found issues", + action=argparse.BooleanOptionalAction, type=bool, default=False) parser.add_argument("--coverage", help="show coverage of the checks", - action=argparse.BooleanOptionalAction, default=False) + action=argparse.BooleanOptionalAction,type=bool, default=False) args = parser.parse_args() # Get repository information @@ -32,8 +32,18 @@ def main(): """ args = parse_args() + # No action can be performed without the Beman Standard downloaded. beman_standard = download_beman_standard() - run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace, coverage=args.coverage) + if not beman_standard or len(beman_standard) == 0: + print("Failed to download the beman standard. STOP.") + return + + # Actually run the checks. + run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace) + + # Show coverage. + if args.coverage: + print_coverage(args.repo_info, beman_standard) if __name__ == "__main__": main() diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 002cc589..15347fb6 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -50,11 +50,10 @@ def get_beman_standard_check(beman_standard, check_name): return next(filter(lambda bs_check: bs_check[0] == check_name, beman_standard), None) -def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, coverage=False): +def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False): """ Run the checks pipeline for The Beman Standard. - If fix_inplace is True, fix the issues inplace. - If coverage is True, print the coverage. + Read-only checks if fix_inplace is False, otherwise try to fix the issues in-place. """ print("Checks pipeline started ...\n") @@ -78,27 +77,19 @@ def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, coverage=F print("\nChecks pipeline completed.") sys.stdout.flush() - if coverage: - print_coverage(repo_info, beman_standard) - def print_coverage(repo_info, beman_standard): """ Print The Beman Standard coverage. """ - # Actual implemented checks. all_implemented_checks = [generic_check( repo_info, beman_standard) for generic_check in get_all_implemented_checks()] - all_bs_implemented_checks = [generic_check for generic_check in all_implemented_checks if get_beman_standard_check( - beman_standard, generic_check.name)] + all_bs_implemented_checks = [check for check in all_implemented_checks if get_beman_standard_check( + beman_standard, check.name) is not None] passed_bs_checks = [ - bs_check for bs_check in all_bs_implemented_checks if bs_check.base_check() and bs_check.check()] - - # Stats about the clang-tidy checks coverage over The Beman Standard. - total_bs_checks = len(beman_standard) - total_implemented_bs_checks = len(all_bs_implemented_checks) + check for check in all_bs_implemented_checks if check.base_check() and check.check()] + coverage = round(len(passed_bs_checks) / len(beman_standard) * 100, 2) + # print(f"(beman-tidy implementation status: {len(all_bs_implemented_checks)}/{len(beman_standard)} checks implemented.)") print( - f"repo coverage over The Beman Standard: {len(passed_bs_checks) / total_bs_checks * 100}% ({len(passed_bs_checks)}/{total_bs_checks} checks passed).") - print( - f"clang-tidy coverage over The Beman Standard: {total_implemented_bs_checks / total_bs_checks * 100}% ({total_implemented_bs_checks}/{total_bs_checks} checks implemented).") + f"\nCoverage for '{repo_info['name']}' repository: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).") From b9bc07d9dba97c148b5f5388e6d053da6b3f90ee Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 14:57:23 +0100 Subject: [PATCH 042/371] beman-tidy: remove --coverage option --- tools/beman-tidy/beman-tidy | 5 +---- tools/beman-tidy/lib/pipeline.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 89d32382..129aeb43 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -15,8 +15,6 @@ def parse_args(): required=True, type=str) parser.add_argument("--fix-inplace", help="try to automatically fix found issues", action=argparse.BooleanOptionalAction, type=bool, default=False) - parser.add_argument("--coverage", help="show coverage of the checks", - action=argparse.BooleanOptionalAction,type=bool, default=False) args = parser.parse_args() # Get repository information @@ -42,8 +40,7 @@ def main(): run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace) # Show coverage. - if args.coverage: - print_coverage(args.repo_info, beman_standard) + print_coverage(args.repo_info, beman_standard) if __name__ == "__main__": main() diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 15347fb6..f25f426b 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -92,4 +92,4 @@ def print_coverage(repo_info, beman_standard): # print(f"(beman-tidy implementation status: {len(all_bs_implemented_checks)}/{len(beman_standard)} checks implemented.)") print( - f"\nCoverage for '{repo_info['name']}' repository: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).") + f"\nbeman-tidy coverage: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).") From 4c88a1e8c2368302d7df814e63115a2b1b27f4ab Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 15:47:06 +0100 Subject: [PATCH 043/371] beman-tidy: add --verbose --- tools/beman-tidy/beman-tidy | 4 ++- .../beman-tidy/lib/checks/base/base_check.py | 9 +---- tools/beman-tidy/lib/pipeline.py | 33 +++++++++++-------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 129aeb43..cb594539 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -15,6 +15,8 @@ def parse_args(): required=True, type=str) parser.add_argument("--fix-inplace", help="try to automatically fix found issues", action=argparse.BooleanOptionalAction, type=bool, default=False) + parser.add_argument("--verbose", help="print verbose output for each check", + action=argparse.BooleanOptionalAction, type=bool, default=False) args = parser.parse_args() # Get repository information @@ -37,7 +39,7 @@ def main(): return # Actually run the checks. - run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace) + run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace, verbose=args.verbose) # Show coverage. print_coverage(args.repo_info, beman_standard) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index f8adb758..20ddc6f2 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -36,7 +36,6 @@ def __init__(self, repo_info, beman_standard, check_name): assert self.full_text_body is not None self.log_level = 'ERROR' if self.type == 'REQUIREMENT' else 'WARNING' - # log is disabled by default, call set_log_enabled(True) to enable it self.log_enabled = False self.repo_info = repo_info @@ -90,11 +89,5 @@ def log(self, message, enabled=True): e.g. [ERROR][TOPLEVEL.CMAKE]: Missing top level CMakeLists.txt.' """ - if enabled: + if self.log_enabled and enabled: print(f'[{self.log_level:<15}][{self.name:<25}]: {message}') - - def set_log_enabled(self, log_enabled): - """ - Set the log_enabled flag. - """ - self.log_enabled = log_enabled diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index f25f426b..3a0f4a19 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -50,31 +50,36 @@ def get_beman_standard_check(beman_standard, check_name): return next(filter(lambda bs_check: bs_check[0] == check_name, beman_standard), None) -def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False): +def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, verbose=False): """ Run the checks pipeline for The Beman Standard. Read-only checks if fix_inplace is False, otherwise try to fix the issues in-place. """ + def log(msg): + if verbose: + print(msg) - print("Checks pipeline started ...\n") + log("beman-tidy started ...\n") for generic_check in get_all_implemented_checks(): bs_check = generic_check(repo_info, beman_standard) - print( + bs_check.log_enabled = verbose + + log( f"Running check [{bs_check.type}][{bs_check.name}] ... ") - if bs_check.base_check() and bs_check.check(): - print(f"\tcheck [{bs_check.type}][{bs_check.name}] ... PASSED\n") + if not fix_inplace: + if bs_check.base_check() and bs_check.check(): + log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... PASSED\n") + else: + log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... FAILED\n") else: - print(f"\tcheck [{bs_check.type}][{bs_check.name}] ... FAILED\n") - - if fix_inplace: - if bs_check.fix(): - bs_check.log(f"\tcheck '{bs_check.name}' ... FIXED.") - else: - bs_check.log( - f"\tcheck '{bs_check.name}' ... FAILED TO FIX INPLACE. Please manually fix it!") + if bs_check.fix(): + log(f"\tcheck '{bs_check.name}' ... (already) FIXED.") + else: + log( + f"\tcheck '{bs_check.name}' ... FAILED TO FIX INPLACE. Please manually fix it!") - print("\nChecks pipeline completed.") + log("\nbeman-tidy finished.\n") sys.stdout.flush() From 469de9b611d66f126f5e56bc89ab31d1ff948f1b Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 16:08:21 +0100 Subject: [PATCH 044/371] beman-tidy: use colors --- tools/beman-tidy/lib/checks/system/git.py | 2 +- tools/beman-tidy/lib/pipeline.py | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index 55cb6858..cbeb03f1 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -13,7 +13,7 @@ class BSCheckFixInplaceIncompatibleWithUnstagedChanges(BSCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, - 'FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES') + 'NO_UNSTAGED_CHANGES') def check(self): """ diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 3a0f4a19..f59b988e 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -58,6 +58,8 @@ def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, verbose=Fa def log(msg): if verbose: print(msg) + red_failed = "\033[91mFAILED\033[0m" + green_passed = "\033[92mPASSED\033[0m" log("beman-tidy started ...\n") for generic_check in get_all_implemented_checks(): @@ -67,17 +69,10 @@ def log(msg): log( f"Running check [{bs_check.type}][{bs_check.name}] ... ") - if not fix_inplace: - if bs_check.base_check() and bs_check.check(): - log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... PASSED\n") - else: - log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... FAILED\n") + if (bs_check.base_check() and bs_check.check()) or (fix_inplace and bs_check.fix()): + log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {green_passed}\n") else: - if bs_check.fix(): - log(f"\tcheck '{bs_check.name}' ... (already) FIXED.") - else: - log( - f"\tcheck '{bs_check.name}' ... FAILED TO FIX INPLACE. Please manually fix it!") + log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {red_failed}\n") log("\nbeman-tidy finished.\n") sys.stdout.flush() From 2741d0f1ba4e532d9c768330c571b7e96151e329 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 16:14:40 +0100 Subject: [PATCH 045/371] beman-tidy: update docs with usages --- tools/beman-tidy/README.md | 132 +++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 36 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 7ec9853b..86b82af7 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -16,60 +16,120 @@ TODO: Add an installation section. ## Usage -TODO: Add a usage section. - ```shell $ ./tools/beman-tidy/beman-tidy --help +usage: beman-tidy [-h] --repo-path REPO_PATH [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] + +optional arguments: -h, --help show this help message and exit - --repo_path REPO_PATH + --repo-path REPO_PATH path to the repository to check - --fix_inplace, --no-fix_inplace + --fix-inplace, --no-fix-inplace try to automatically fix found issues (default: False) - --coverage, --no-coverage - show coverage of the checks (default: False) + --verbose, --no-verbose + print verbose output for each check (default: False) +``` + +More examples: + +```shell +# Run checks and DO NOT fix issues and DO NOT print verbose output. +$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar +beman-tidy coverage: 11.11% (5/45 checks passed). + +# Run checks and DO NOT fix issues and print verbose output. +$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose +beman-tidy started ... + +Running check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... + check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED + +Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... +[ERROR ][TOPLEVEL.CHANGELOG ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/CHANGELOG.md' does not exist. + check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... FAILED + +Running check [REQUIREMENT][TOPLEVEL.CMAKE] ... + check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED + +Running check [REQUIREMENT][TOPLEVEL.LICENSE] ... + check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED + +Running check [REQUIREMENT][TOPLEVEL.README] ... + check [REQUIREMENT][TOPLEVEL.README] ... PASSED + +Running check [REQUIREMENT][CHANGELOG.TITLE] ... +[ERROR ][CHANGELOG.TITLE ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/Changelog.md' does not exist. + check [REQUIREMENT][CHANGELOG.TITLE] ... FAILED + +Running check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... +[ERROR ][CHANGELOG.LIBRARY_STATUS ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/Changelog.md' does not exist. + check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... FAILED + +Running check [RECOMMENDATION][README.TITLE] ... + check [RECOMMENDATION][README.TITLE] ... FAILED + +Running check [REQUIREMENT][README.BADGES] ... +[ERROR ][README.BADGES ]: Only one line of badges is allowed. +[ERROR ][README.BADGES ]: First line of README.md must contain badges. + check [REQUIREMENT][README.BADGES] ... FAILED + +Running check [RECOMMENDATION][README.IMPLEMENTS] ... + check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED + +Running check [REQUIREMENT][README.LIBRARY_STATUS] ... + check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED + + +beman-tidy finished. + + +beman-tidy coverage: 11.11% (5/45 checks passed). + +# Run checks and fix issues and print verbose output. +$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose --fix-inplace +beman-tidy started ... -# no errors found example -$ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar -Checks pipeline started ... +Running check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... + check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED -Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... - check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... PASSED +Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... +[ERROR ][TOPLEVEL.CHANGELOG ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/CHANGELOG.md' does not exist. + check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... FAILED -... +Running check [REQUIREMENT][TOPLEVEL.CMAKE] ... + check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED -Checks pipeline completed. -# errors found example -$ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar -Checks pipeline started ... +Running check [REQUIREMENT][TOPLEVEL.LICENSE] ... + check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED -Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... - check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... FAILED +Running check [REQUIREMENT][TOPLEVEL.README] ... + check [REQUIREMENT][TOPLEVEL.README] ... PASSED -... +Running check [REQUIREMENT][CHANGELOG.TITLE] ... +[ERROR ][CHANGELOG.TITLE ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/Changelog.md' does not exist. + check [REQUIREMENT][CHANGELOG.TITLE] ... FAILED -Checks pipeline completed. +Running check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... +[ERROR ][CHANGELOG.LIBRARY_STATUS ]: CHANGELOG.md must contain a line for each previous library status with respect to the Beman library maturity model. Initial library status is missing. + check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... FAILED -# errors found + --fix example -$ ./tools/beman-tidy/beman-tidy -beman-tidy is a tool to check the coding standard of The Beman Project. +Running check [RECOMMENDATION][README.TITLE] ... + check [RECOMMENDATION][README.TITLE] ... FAILED -/tools/beman-tidy/beman-tidy --repo_path ../exemplar --fix -Checks pipeline started ... +Running check [REQUIREMENT][README.BADGES] ... +[ERROR ][README.BADGES ]: Only one line of badges is allowed. +[ERROR ][README.BADGES ]: First line of README.md must contain badges. + check [REQUIREMENT][README.BADGES] ... FAILED -Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... - check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... FAILED +Running check [RECOMMENDATION][README.IMPLEMENTS] ... + check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED -[ERROR ][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES]: The fix cannot be applied inplace. Please commit or stash your changes. STOP. +Running check [REQUIREMENT][README.LIBRARY_STATUS] ... + check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED -# coverage example -$ ./tools/beman-tidy/beman-tidy --repo_path ../exemplar --coverage -Checks pipeline started ... -Running check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... - check [REQUIREMENT][FIX_INPLACE_INCOMPATIBLE_WITH_UNSTAGED_CHANGES] ... PASSED +beman-tidy finished. -Checks pipeline completed. -repo coverage over The Beman Standard: 0.0% (0/43 checks passed). -clang-tidy coverage over The Beman Standard: 0.0% (0/43 checks implemented). +beman-tidy coverage: 17.78% (8/45 checks passed). ``` From 7b0af890d2eac23685730ab8e04bd8930641a23d Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 16:20:22 +0100 Subject: [PATCH 046/371] beman-tidy: update docs with install instructions --- requirements.txt | 2 ++ tools/beman-tidy/README.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..78f66344 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Markdown==3.4.4 +Requests==2.32.3 diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 86b82af7..7053f679 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -12,7 +12,9 @@ TODO: Add a description. ## Installation -TODO: Add an installation section. +```shell +$ pip3 install -r requirements.txt +``` ## Usage From 52d2103b7a849795b574034c857b7eafdafdf763 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 16:34:02 +0100 Subject: [PATCH 047/371] beman-tidy: add --dry-mode --- tools/beman-tidy/README.md | 73 ++++++++++++++------------------ tools/beman-tidy/beman-tidy | 4 +- tools/beman-tidy/lib/pipeline.py | 7 ++- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 7053f679..cba55d04 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -19,115 +19,106 @@ $ pip3 install -r requirements.txt ## Usage ```shell +# Display help. $ ./tools/beman-tidy/beman-tidy --help -usage: beman-tidy [-h] --repo-path REPO_PATH [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] +usage: beman-tidy [-h] --repo-path REPO_PATH [--dry-run | --no-dry-run] [--verbose | --no-verbose] optional arguments: -h, --help show this help message and exit --repo-path REPO_PATH path to the repository to check - --fix-inplace, --no-fix-inplace - try to automatically fix found issues (default: False) + --dry-run, --no-dry-run + DO NOT try to automatically fix found issues (default: False) --verbose, --no-verbose print verbose output for each check (default: False) -``` - -More examples: -```shell -# Run checks and DO NOT fix issues and DO NOT print verbose output. +# Run beman-tidy on the exemplar repository (automatically fix issues). $ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar -beman-tidy coverage: 11.11% (5/45 checks passed). +beman-tidy coverage: 17.78% (8/45 checks passed). -# Run checks and DO NOT fix issues and print verbose output. +# Run beman-tidy on the exemplar repository (automatically fix issues, verbose output). $ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose beman-tidy started ... Running check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... - check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED + check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... -[ERROR ][TOPLEVEL.CHANGELOG ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/CHANGELOG.md' does not exist. - check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... FAILED + check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... PASSED Running check [REQUIREMENT][TOPLEVEL.CMAKE] ... - check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED + check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED Running check [REQUIREMENT][TOPLEVEL.LICENSE] ... - check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED + check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED Running check [REQUIREMENT][TOPLEVEL.README] ... - check [REQUIREMENT][TOPLEVEL.README] ... PASSED + check [REQUIREMENT][TOPLEVEL.README] ... PASSED Running check [REQUIREMENT][CHANGELOG.TITLE] ... -[ERROR ][CHANGELOG.TITLE ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/Changelog.md' does not exist. - check [REQUIREMENT][CHANGELOG.TITLE] ... FAILED + check [REQUIREMENT][CHANGELOG.TITLE] ... PASSED Running check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... -[ERROR ][CHANGELOG.LIBRARY_STATUS ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/Changelog.md' does not exist. - check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... FAILED + check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... PASSED Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... FAILED + check [RECOMMENDATION][README.TITLE] ... FAILED Running check [REQUIREMENT][README.BADGES] ... [ERROR ][README.BADGES ]: Only one line of badges is allowed. [ERROR ][README.BADGES ]: First line of README.md must contain badges. - check [REQUIREMENT][README.BADGES] ... FAILED + check [REQUIREMENT][README.BADGES] ... FAILED Running check [RECOMMENDATION][README.IMPLEMENTS] ... - check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED + check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED Running check [REQUIREMENT][README.LIBRARY_STATUS] ... - check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED + check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED beman-tidy finished. -beman-tidy coverage: 11.11% (5/45 checks passed). +beman-tidy coverage: 17.78% (8/45 checks passed). -# Run checks and fix issues and print verbose output. -$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose --fix-inplace +# Run beman-tidy on the exemplar repository (dry-run, verbose output). +$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose --dry-run beman-tidy started ... Running check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... - check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED + check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... -[ERROR ][TOPLEVEL.CHANGELOG ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/CHANGELOG.md' does not exist. - check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... FAILED + check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... PASSED Running check [REQUIREMENT][TOPLEVEL.CMAKE] ... - check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED + check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED Running check [REQUIREMENT][TOPLEVEL.LICENSE] ... - check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED + check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED Running check [REQUIREMENT][TOPLEVEL.README] ... - check [REQUIREMENT][TOPLEVEL.README] ... PASSED + check [REQUIREMENT][TOPLEVEL.README] ... PASSED Running check [REQUIREMENT][CHANGELOG.TITLE] ... -[ERROR ][CHANGELOG.TITLE ]: The file '/Users/dariusn/dev/dn/git/Beman/exemplar/Changelog.md' does not exist. - check [REQUIREMENT][CHANGELOG.TITLE] ... FAILED + check [REQUIREMENT][CHANGELOG.TITLE] ... PASSED Running check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... -[ERROR ][CHANGELOG.LIBRARY_STATUS ]: CHANGELOG.md must contain a line for each previous library status with respect to the Beman library maturity model. Initial library status is missing. - check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... FAILED + check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... PASSED Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... FAILED + check [RECOMMENDATION][README.TITLE] ... FAILED Running check [REQUIREMENT][README.BADGES] ... [ERROR ][README.BADGES ]: Only one line of badges is allowed. [ERROR ][README.BADGES ]: First line of README.md must contain badges. - check [REQUIREMENT][README.BADGES] ... FAILED + check [REQUIREMENT][README.BADGES] ... FAILED Running check [RECOMMENDATION][README.IMPLEMENTS] ... - check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED + check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED Running check [REQUIREMENT][README.LIBRARY_STATUS] ... - check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED + check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED beman-tidy finished. diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index cb594539..427f7d1b 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -13,7 +13,7 @@ def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("--repo-path", help="path to the repository to check", required=True, type=str) - parser.add_argument("--fix-inplace", help="try to automatically fix found issues", + parser.add_argument("--dry-run", help="DO NOT try to automatically fix found issues", action=argparse.BooleanOptionalAction, type=bool, default=False) parser.add_argument("--verbose", help="print verbose output for each check", action=argparse.BooleanOptionalAction, type=bool, default=False) @@ -39,7 +39,7 @@ def main(): return # Actually run the checks. - run_checks_pipeline(args.repo_info, beman_standard, fix_inplace=args.fix_inplace, verbose=args.verbose) + run_checks_pipeline(args.repo_info, beman_standard, dry_run=args.dry_run, verbose=args.verbose) # Show coverage. print_coverage(args.repo_info, beman_standard) diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index f59b988e..62ffcb5b 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -50,10 +50,10 @@ def get_beman_standard_check(beman_standard, check_name): return next(filter(lambda bs_check: bs_check[0] == check_name, beman_standard), None) -def run_checks_pipeline(repo_info, beman_standard, fix_inplace=False, verbose=False): +def run_checks_pipeline(repo_info, beman_standard, dry_run=False, verbose=False): """ Run the checks pipeline for The Beman Standard. - Read-only checks if fix_inplace is False, otherwise try to fix the issues in-place. + Read-only checks if dry_run is True, otherwise try to fix the issues in-place. """ def log(msg): if verbose: @@ -69,7 +69,7 @@ def log(msg): log( f"Running check [{bs_check.type}][{bs_check.name}] ... ") - if (bs_check.base_check() and bs_check.check()) or (fix_inplace and bs_check.fix()): + if (bs_check.base_check() and bs_check.check()) or (not dry_run and bs_check.fix()): log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {green_passed}\n") else: log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {red_failed}\n") @@ -90,6 +90,5 @@ def print_coverage(repo_info, beman_standard): check for check in all_bs_implemented_checks if check.base_check() and check.check()] coverage = round(len(passed_bs_checks) / len(beman_standard) * 100, 2) - # print(f"(beman-tidy implementation status: {len(all_bs_implemented_checks)}/{len(beman_standard)} checks implemented.)") print( f"\nbeman-tidy coverage: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).") From 5b81b2f6ed7f99fb919cb13919962c0a1b13f551 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 16:50:58 +0100 Subject: [PATCH 048/371] beman-tidy: improve displayed data --- tools/beman-tidy/README.md | 55 +++----------------------------- tools/beman-tidy/lib/pipeline.py | 33 +++++++++++++------ 2 files changed, 29 insertions(+), 59 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index cba55d04..56807782 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -34,60 +34,14 @@ optional arguments: # Run beman-tidy on the exemplar repository (automatically fix issues). $ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar -beman-tidy coverage: 17.78% (8/45 checks passed). +Summary: 8 checks PASSED, 2 checks FAILED, 35 skipped (not implemented). + +Coverage: 17.78% (8/45 checks passed). # Run beman-tidy on the exemplar repository (automatically fix issues, verbose output). $ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose beman-tidy started ... -Running check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... - check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED - -Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... - check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... PASSED - -Running check [REQUIREMENT][TOPLEVEL.CMAKE] ... - check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED - -Running check [REQUIREMENT][TOPLEVEL.LICENSE] ... - check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED - -Running check [REQUIREMENT][TOPLEVEL.README] ... - check [REQUIREMENT][TOPLEVEL.README] ... PASSED - -Running check [REQUIREMENT][CHANGELOG.TITLE] ... - check [REQUIREMENT][CHANGELOG.TITLE] ... PASSED - -Running check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... - check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... PASSED - -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... FAILED - -Running check [REQUIREMENT][README.BADGES] ... -[ERROR ][README.BADGES ]: Only one line of badges is allowed. -[ERROR ][README.BADGES ]: First line of README.md must contain badges. - check [REQUIREMENT][README.BADGES] ... FAILED - -Running check [RECOMMENDATION][README.IMPLEMENTS] ... - check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED - -Running check [REQUIREMENT][README.LIBRARY_STATUS] ... - check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED - - -beman-tidy finished. - - -beman-tidy coverage: 17.78% (8/45 checks passed). - -# Run beman-tidy on the exemplar repository (dry-run, verbose output). -$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose --dry-run -beman-tidy started ... - -Running check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... - check [REQUIREMENT][NO_UNSTAGED_CHANGES] ... PASSED - Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... PASSED @@ -123,6 +77,7 @@ Running check [REQUIREMENT][README.LIBRARY_STATUS] ... beman-tidy finished. +Summary: 8 checks PASSED, 2 checks FAILED, 35 skipped (not implemented). -beman-tidy coverage: 17.78% (8/45 checks passed). +Coverage: 17.78% (8/45 checks passed). ``` diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 62ffcb5b..f331c051 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -21,9 +21,6 @@ def get_all_implemented_checks(): Returns a list of checks that need to be run. """ return [ - # Validate CLI arguments - BSCheckFixInplaceIncompatibleWithUnstagedChanges, - # TOPLEVEL BSTopLevelChangelogCheck, BSTopLevelCMakeListsCheck, @@ -58,23 +55,41 @@ def run_checks_pipeline(repo_info, beman_standard, dry_run=False, verbose=False) def log(msg): if verbose: print(msg) - red_failed = "\033[91mFAILED\033[0m" - green_passed = "\033[92mPASSED\033[0m" - log("beman-tidy started ...\n") - for generic_check in get_all_implemented_checks(): + def run_check(generic_check, log_enabled=verbose): bs_check = generic_check(repo_info, beman_standard) - bs_check.log_enabled = verbose + bs_check.log_enabled = log_enabled log( f"Running check [{bs_check.type}][{bs_check.name}] ... ") if (bs_check.base_check() and bs_check.check()) or (not dry_run and bs_check.fix()): log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {green_passed}\n") + return True else: log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {red_failed}\n") + return False + + red_failed = "\033[91mFAILED\033[0m" + green_passed = "\033[92mPASSED\033[0m" + + log("beman-tidy started ...\n") + + # Internal checks + if dry_run: + run_check(BSCheckFixInplaceIncompatibleWithUnstagedChanges, + log_enabled=False) + + cnt_passed = 0 + cnt_failed = 0 + for generic_check in get_all_implemented_checks(): + if run_check(generic_check): + cnt_passed += 1 + else: + cnt_failed += 1 log("\nbeman-tidy finished.\n") + print(f"Summary: {cnt_passed} checks {green_passed}, {cnt_failed} checks {red_failed}, {len(beman_standard) - len(get_all_implemented_checks())} skipped (not implemented).") sys.stdout.flush() @@ -91,4 +106,4 @@ def print_coverage(repo_info, beman_standard): coverage = round(len(passed_bs_checks) / len(beman_standard) * 100, 2) print( - f"\nbeman-tidy coverage: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).") + f"\n\033[93mCoverage: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).\033[0m") From c1f9705d6960e98364c63653bf5d54cb8cf58e19 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 16:56:52 +0100 Subject: [PATCH 049/371] beman-tidy: move requirements.txt --- tools/beman-tidy/README.md | 2 -- tools/beman-tidy/lib/utils/__init__.py | 0 requirements.txt => tools/beman-tidy/requirements.txt | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 tools/beman-tidy/lib/utils/__init__.py rename requirements.txt => tools/beman-tidy/requirements.txt (64%) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 56807782..0111461c 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -6,8 +6,6 @@ SPDX-License-Identifier: 2.0 license with LLVM exceptions ## Description -TODO: Add a 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). ## Installation diff --git a/tools/beman-tidy/lib/utils/__init__.py b/tools/beman-tidy/lib/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/requirements.txt b/tools/beman-tidy/requirements.txt similarity index 64% rename from requirements.txt rename to tools/beman-tidy/requirements.txt index 78f66344..b7e2f16e 100644 --- a/requirements.txt +++ b/tools/beman-tidy/requirements.txt @@ -1,2 +1,3 @@ +GitPython==3.1.44 Markdown==3.4.4 Requests==2.32.3 From 51b9a308f31894ffe48954e767246fd3cb243411 Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Wed, 12 Feb 2025 17:21:20 +0100 Subject: [PATCH 050/371] beman-tidy: move params for run_checks_pipeline --- tools/beman-tidy/beman-tidy | 2 +- tools/beman-tidy/lib/pipeline.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 427f7d1b..5ba65f6b 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -39,7 +39,7 @@ def main(): return # Actually run the checks. - run_checks_pipeline(args.repo_info, beman_standard, dry_run=args.dry_run, verbose=args.verbose) + run_checks_pipeline(args, beman_standard) # Show coverage. print_coverage(args.repo_info, beman_standard) diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index f331c051..926035be 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -47,23 +47,24 @@ def get_beman_standard_check(beman_standard, check_name): return next(filter(lambda bs_check: bs_check[0] == check_name, beman_standard), None) -def run_checks_pipeline(repo_info, beman_standard, dry_run=False, verbose=False): +def run_checks_pipeline(args, beman_standard): """ Run the checks pipeline for The Beman Standard. - Read-only checks if dry_run is True, otherwise try to fix the issues in-place. + Read-only checks if args.dry_run is True, otherwise try to fix the issues in-place. + Verbosity is controlled by args.verbose. """ def log(msg): - if verbose: + if args.verbose: print(msg) - def run_check(generic_check, log_enabled=verbose): - bs_check = generic_check(repo_info, beman_standard) + def run_check(generic_check, log_enabled=args.verbose): + bs_check = generic_check(args.repo_info, beman_standard) bs_check.log_enabled = log_enabled log( f"Running check [{bs_check.type}][{bs_check.name}] ... ") - if (bs_check.base_check() and bs_check.check()) or (not dry_run and bs_check.fix()): + if (bs_check.base_check() and bs_check.check()) or (not args.dry_run and bs_check.fix()): log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {green_passed}\n") return True else: @@ -76,7 +77,7 @@ def run_check(generic_check, log_enabled=verbose): log("beman-tidy started ...\n") # Internal checks - if dry_run: + if args.dry_run: run_check(BSCheckFixInplaceIncompatibleWithUnstagedChanges, log_enabled=False) From 159bc4a70f49ed57e08ec4047cccf6355bb295cf Mon Sep 17 00:00:00 2001 From: Darius Neatu Date: Thu, 13 Feb 2025 11:14:12 +0100 Subject: [PATCH 051/371] beman-tidy: typo in docs --- tools/beman-tidy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 0111461c..1f2bdba8 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -1,4 +1,4 @@ -# beman-tidy: Codebase Beminification Tool +# beman-tidy: Codebase Bemanification Tool + TODO \ No newline at end of file From 5b8fad30987baba161db109da5d1e9b6555cd06b Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Mon, 24 Feb 2025 23:02:42 +0000 Subject: [PATCH 068/371] add more docs --- devcontainer/README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/devcontainer/README.md b/devcontainer/README.md index 62380815..a2c4c8ad 100644 --- a/devcontainer/README.md +++ b/devcontainer/README.md @@ -2,4 +2,23 @@ -TODO \ No newline at end of file +This folder contains the infrastructure for beman project's +generic devcontainer image. You can checkout the image in beman's +[GitHub Packages page](https://github.com/orgs/bemanproject/packages/container/package/devcontainers). + +The image is build on top of GitHub's +[C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp) +for ubuntu 24.04. + +The image includes: + +- The latest CMake from kitware's apt repository +- GNU compiler version 14 (this is configurable via docker build arg) + +## Building your own image + +You can build your own beman devcontainer image with: + +```bash +docker build devcontainer/ +``` \ No newline at end of file From 7d0846b419f2a31b529cc89a35b055188fc4e4ce Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:08:26 -0500 Subject: [PATCH 069/371] Format --- .devcontainer/docker_dev_container/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/docker_dev_container/devcontainer.json b/.devcontainer/docker_dev_container/devcontainer.json index 2b1a20e8..6707a25b 100644 --- a/.devcontainer/docker_dev_container/devcontainer.json +++ b/.devcontainer/docker_dev_container/devcontainer.json @@ -8,6 +8,6 @@ "enableNonRootDocker": true, "moby": false }, - "ghcr.io/devcontainers-extra/features/pre-commit:2": {} + "ghcr.io/devcontainers-extra/features/pre-commit:2": {} } -} \ No newline at end of file +} From ded3d83a0035771dfacb00fe1dfa9b669408dc71 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 26 Feb 2025 00:37:50 +0000 Subject: [PATCH 070/371] update docker file to install pre-commit correctly --- devcontainer/Dockerfile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/devcontainer/Dockerfile b/devcontainer/Dockerfile index 6a9a29d4..9e1bb58e 100644 --- a/devcontainer/Dockerfile +++ b/devcontainer/Dockerfile @@ -10,8 +10,6 @@ RUN bash < Date: Wed, 26 Feb 2025 00:38:52 +0000 Subject: [PATCH 071/371] only use `beman/devcontainers` on main branch --- .github/workflows/build_devcontainer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 317acad9..b7111dcf 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -25,7 +25,7 @@ jobs: id: image_name run: | image_name=${{ env.DEPLOY_IMAGE_NAME }} - if [ "${{ github.repository_owner }}" != "beman" ]; then + if [ "${{ github.repository }}/${{ github.ref }}" != "beman/infra/refs/heads/main" ]; then image_name=${{ env.DEBUG_IMAGE_NAME }} fi echo "computed image name: $image_name" From 39478e8339d4825651173de6556ad0e399d92e84 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 26 Feb 2025 00:51:01 +0000 Subject: [PATCH 072/371] matrix-fy --- .github/workflows/build_devcontainer.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index b7111dcf..45d124a1 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -19,7 +19,12 @@ permissions: jobs: build-and-push-devcontainer-image: runs-on: ubuntu-latest - name: Update devcontainer + strategy: + fail-fast: false + matrix: + include: + - version: 14 + name: Update devcontainer gnu-${{ matrix.version }} steps: - name: Compute Image Name id: image_name @@ -43,8 +48,8 @@ jobs: with: context: devcontainer build-args: | - gnu_version=14 + gnu_version=${{ matrix.version }} push: true - tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:gnu-14 + tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:gnu-${{ matrix.version }} # https://github.com/docker/build-push-action/issues/894 provenance: false From 8db1077a5d5081f5da7ab3e64ca0444ba4a66093 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 26 Feb 2025 00:55:25 +0000 Subject: [PATCH 073/371] Fix workflow trigger --- .github/workflows/build_devcontainer.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 45d124a1..da9d05df 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -5,6 +5,7 @@ name: Publish Beman devcontainers on: push: paths: + - ".github/workflows/build_devcontainer.yml" - "devcontainer/**" workflow_dispatch: From 8dd3aab2e5726a31511856529b038b4624c0c3ee Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 26 Feb 2025 01:08:58 +0000 Subject: [PATCH 074/371] allow build of llvm --- .github/workflows/build_devcontainer.yml | 12 +++++--- devcontainer/Dockerfile | 21 +++++--------- devcontainer/install_compiler.sh | 36 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 devcontainer/install_compiler.sh diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index da9d05df..a003c32f 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -24,8 +24,11 @@ jobs: fail-fast: false matrix: include: - - version: 14 - name: Update devcontainer gnu-${{ matrix.version }} + - kind: gnu + version: 14 + - kind: llvm + version: 19 + name: Update devcontainer ${{ matrix.kind }}-${{ matrix.version }} steps: - name: Compute Image Name id: image_name @@ -49,8 +52,9 @@ jobs: with: context: devcontainer build-args: | - gnu_version=${{ matrix.version }} + compiler_kind=${{ matrix.kind }} + compiler_version=${{ matrix.version }} push: true - tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:gnu-${{ matrix.version }} + tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:${{ matrix.kind }}-${{ matrix.version }} # https://github.com/docker/build-push-action/issues/894 provenance: false diff --git a/devcontainer/Dockerfile b/devcontainer/Dockerfile index 9e1bb58e..5c2242e1 100644 --- a/devcontainer/Dockerfile +++ b/devcontainer/Dockerfile @@ -2,6 +2,9 @@ FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 +USER vscode +WORKDIR /tmp + # Latest CMake needed for most of the beman libraries, # so we need to install via kitware's apt repo RUN bash < Date: Tue, 25 Feb 2025 20:35:42 -0500 Subject: [PATCH 075/371] Update README.md --- devcontainer/README.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/devcontainer/README.md b/devcontainer/README.md index a2c4c8ad..c878c871 100644 --- a/devcontainer/README.md +++ b/devcontainer/README.md @@ -3,7 +3,7 @@ This folder contains the infrastructure for beman project's -generic devcontainer image. You can checkout the image in beman's +generic devcontainer image. You can checkout available images in beman's [GitHub Packages page](https://github.com/orgs/bemanproject/packages/container/package/devcontainers). The image is build on top of GitHub's @@ -13,7 +13,29 @@ for ubuntu 24.04. The image includes: - The latest CMake from kitware's apt repository -- GNU compiler version 14 (this is configurable via docker build arg) +- Latest compiler based on build args (gnu or llvm) installed from the universe repository +- [pre-commit](https://pre-commit.com/), the standard linter manager across beman + +## Example devcontainer setup + +```json +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp + +{ + "name": "Beman Generic Devcontainer", + "image": "ghcr.io/bemanproject/devcontainers:gnu-14", + "postCreateCommand": "pre-commit", + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ] + } + } +} +``` ## Building your own image @@ -21,4 +43,4 @@ You can build your own beman devcontainer image with: ```bash docker build devcontainer/ -``` \ No newline at end of file +``` From f647ba2c358098ded54935aafc827d3b932d7445 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:36:42 -0500 Subject: [PATCH 076/371] Fix license header in the example devcontainer setup --- devcontainer/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/devcontainer/README.md b/devcontainer/README.md index c878c871..4eb40d87 100644 --- a/devcontainer/README.md +++ b/devcontainer/README.md @@ -19,9 +19,7 @@ The image includes: ## Example devcontainer setup ```json -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/cpp - +// SPDX-License-Identifier: 2.0 license with LLVM exceptions { "name": "Beman Generic Devcontainer", "image": "ghcr.io/bemanproject/devcontainers:gnu-14", From 027d362c431dcb5e0d3d90a4c8a8e2b74bf517c0 Mon Sep 17 00:00:00 2001 From: Bret Brown Date: Sun, 26 Jan 2025 15:52:28 -0500 Subject: [PATCH 077/371] Inject FetchContent logic Problem ------- **Given**: A sandbox environment is an environment where dependencies are all provided but access to the internet is not. Also take as a given that the build for this project happens in an environment that meets that description. **When**: Configuring this project with any of the provided approaches. For instance: ``` cmake -B build -S . ``` **Then**: The configuration step hangs or fails, depending on the nature of the sandboxed environment. Solution -------- Move to a `find_package` first implementation for the `CMakeLists.txt` of this project. Using `FetchContent` is still trivial, using the new functionality in `cmake/use-fetch-content.cmake` as documented in the updates to `README.md` included in this commit. Signed-off-by: Bret Brown --- cmake/use-fetch-content.cmake | 175 ++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 cmake/use-fetch-content.cmake diff --git a/cmake/use-fetch-content.cmake b/cmake/use-fetch-content.cmake new file mode 100644 index 00000000..606c007d --- /dev/null +++ b/cmake/use-fetch-content.cmake @@ -0,0 +1,175 @@ +cmake_minimum_required(VERSION 3.24) + +if(NOT BEMAN_EXEMPLAR_LOCKFILE) + set(BEMAN_EXEMPLAR_LOCKFILE + "lockfile.json" + CACHE FILEPATH + "Path to the dependency lockfile for the Beman Exemplar." + ) +endif() + +set(BemanExemplar_projectDir "${CMAKE_CURRENT_LIST_DIR}/..") +message(TRACE "BemanExemplar_projectDir=\"${BemanExemplar_projectDir}\"") + +message(TRACE "BEMAN_EXEMPLAR_LOCKFILE=\"${BEMAN_EXEMPLAR_LOCKFILE}\"") +file( + REAL_PATH + "${BEMAN_EXEMPLAR_LOCKFILE}" + BemanExemplar_lockfile + BASE_DIRECTORY "${BemanExemplar_projectDir}" + EXPAND_TILDE +) +message(DEBUG "Using lockfile: \"${BemanExemplar_lockfile}\"") + +# Force CMake to reconfigure the project if the lockfile changes +set_property( + DIRECTORY "${BemanExemplar_projectDir}" + APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS "${BemanExemplar_lockfile}" +) + +# For more on the protocol for this function, see: +# https://cmake.org/cmake/help/latest/command/cmake_language.html#provider-commands +function(BemanExemplar_provideDependency method package_name) + # Read the lockfile + file(READ "${BemanExemplar_lockfile}" BemanExemplar_rootObj) + + # Get the "dependencies" field and store it in BemanExemplar_dependenciesObj + string( + JSON + BemanExemplar_dependenciesObj + ERROR_VARIABLE BemanExemplar_error + GET "${BemanExemplar_rootObj}" + "dependencies" + ) + if(BemanExemplar_error) + message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}") + endif() + + # Get the length of the libraries array and store it in BemanExemplar_dependenciesObj + string( + JSON + BemanExemplar_numDependencies + ERROR_VARIABLE BemanExemplar_error + LENGTH "${BemanExemplar_dependenciesObj}" + ) + if(BemanExemplar_error) + message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}") + endif() + + # Loop over each dependency object + math(EXPR BemanExemplar_maxIndex "${BemanExemplar_numDependencies} - 1") + foreach(BemanExemplar_index RANGE "${BemanExemplar_maxIndex}") + set(BemanExemplar_errorPrefix + "${BemanExemplar_lockfile}, dependency ${BemanExemplar_index}" + ) + + # Get the dependency object at BemanExemplar_index + # and store it in BemanExemplar_depObj + string( + JSON + BemanExemplar_depObj + ERROR_VARIABLE BemanExemplar_error + GET "${BemanExemplar_dependenciesObj}" + "${BemanExemplar_index}" + ) + if(BemanExemplar_error) + message( + FATAL_ERROR + "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" + ) + endif() + + # Get the "name" field and store it in BemanExemplar_name + string( + JSON + BemanExemplar_name + ERROR_VARIABLE BemanExemplar_error + GET "${BemanExemplar_depObj}" + "name" + ) + if(BemanExemplar_error) + message( + FATAL_ERROR + "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" + ) + endif() + + # Get the "package_name" field and store it in BemanExemplar_pkgName + string( + JSON + BemanExemplar_pkgName + ERROR_VARIABLE BemanExemplar_error + GET "${BemanExemplar_depObj}" + "package_name" + ) + if(BemanExemplar_error) + message( + FATAL_ERROR + "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" + ) + endif() + + # Get the "git_repository" field and store it in BemanExemplar_repo + string( + JSON + BemanExemplar_repo + ERROR_VARIABLE BemanExemplar_error + GET "${BemanExemplar_depObj}" + "git_repository" + ) + if(BemanExemplar_error) + message( + FATAL_ERROR + "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" + ) + endif() + + # Get the "git_tag" field and store it in BemanExemplar_tag + string( + JSON + BemanExemplar_tag + ERROR_VARIABLE BemanExemplar_error + GET "${BemanExemplar_depObj}" + "git_tag" + ) + if(BemanExemplar_error) + message( + FATAL_ERROR + "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}" + ) + endif() + + if(method STREQUAL "FIND_PACKAGE") + if(package_name STREQUAL BemanExemplar_pkgName) + string( + APPEND + BemanExemplar_debug + "Redirecting find_package calls for ${BemanExemplar_pkgName} " + "to FetchContent logic fetching ${BemanExemplar_repo} at " + "${BemanExemplar_tag} according to ${BemanExemplar_lockfile}." + ) + message(DEBUG "${BemanExemplar_debug}") + FetchContent_Declare( + "${BemanExemplar_name}" + GIT_REPOSITORY "${BemanExemplar_repo}" + GIT_TAG "${BemanExemplar_tag}" + EXCLUDE_FROM_ALL + ) + set(INSTALL_GTEST OFF) # Disable GoogleTest installation + FetchContent_MakeAvailable("${BemanExemplar_name}") + + # Important! _FOUND tells CMake that `find_package` is + # not needed for this package anymore + set("${BemanExemplar_pkgName}_FOUND" TRUE PARENT_SCOPE) + endif() + endif() + endforeach() + + set(GTest_FOUND TRUE PARENT_SCOPE) +endfunction() + +cmake_language( + SET_DEPENDENCY_PROVIDER BemanExemplar_provideDependency + SUPPORTED_METHODS FIND_PACKAGE +) From 3d1c90315c4f89fe1301528eec6e5b559a505c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 11 Mar 2025 21:22:17 +0200 Subject: [PATCH 078/371] Update CODEOWNERS: add @bemanproject/core-reviewers --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..d3be6f19 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @bemanproject/core-reviewers From 9c47aa08176a5136796e506493da5f0874f51114 Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Wed, 12 Mar 2025 11:48:50 -0400 Subject: [PATCH 079/371] Remove extra GTest_FOUND set Remove the extra variable set. --- cmake/use-fetch-content.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/use-fetch-content.cmake b/cmake/use-fetch-content.cmake index 606c007d..63dc9c9b 100644 --- a/cmake/use-fetch-content.cmake +++ b/cmake/use-fetch-content.cmake @@ -165,8 +165,6 @@ function(BemanExemplar_provideDependency method package_name) endif() endif() endforeach() - - set(GTest_FOUND TRUE PARENT_SCOPE) endfunction() cmake_language( From 578285cd0fa518882f4392df1ad55b2f4d94113e Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:18:40 -0400 Subject: [PATCH 080/371] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Darius Neațu Co-authored-by: Radu Nichita <45298861+RaduNichita@users.noreply.github.com> --- devcontainer/Dockerfile | 2 +- devcontainer/README.md | 8 ++++---- devcontainer/install_compiler.sh | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/devcontainer/Dockerfile b/devcontainer/Dockerfile index 5c2242e1..1d6c7bea 100644 --- a/devcontainer/Dockerfile +++ b/devcontainer/Dockerfile @@ -27,4 +27,4 @@ RUN sudo apt-get install -y pipx RUN pipx install pre-commit ENV PATH="/home/vscode/.local/bin:${PATH}" -ENTRYPOINT ["/usr/bin/bash"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/bash"] diff --git a/devcontainer/README.md b/devcontainer/README.md index 4eb40d87..fbb20133 100644 --- a/devcontainer/README.md +++ b/devcontainer/README.md @@ -2,19 +2,19 @@ -This folder contains the infrastructure for beman project's +This folder contains the infrastructure for Beman project's generic devcontainer image. You can checkout available images in beman's [GitHub Packages page](https://github.com/orgs/bemanproject/packages/container/package/devcontainers). The image is build on top of GitHub's [C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp) -for ubuntu 24.04. +for Ubuntu 24.04. The image includes: - The latest CMake from kitware's apt repository - Latest compiler based on build args (gnu or llvm) installed from the universe repository -- [pre-commit](https://pre-commit.com/), the standard linter manager across beman +- [pre-commit](https://pre-commit.com/), the standard linter manager across Beman ## Example devcontainer setup @@ -37,7 +37,7 @@ The image includes: ## Building your own image -You can build your own beman devcontainer image with: +You can build your own Beman devcontainer image with: ```bash docker build devcontainer/ diff --git a/devcontainer/install_compiler.sh b/devcontainer/install_compiler.sh index 573ba196..7ebdafdc 100644 --- a/devcontainer/install_compiler.sh +++ b/devcontainer/install_compiler.sh @@ -2,11 +2,11 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception set -e - +set +x TOOL=$1 VERSION=$2 -echo "Install $TOOL at: $VERSION" +echo "Install ${TOOL} at: ${VERSION}" shopt -s nocasematch if [ "$TOOL" = "gnu" ]; then @@ -24,7 +24,7 @@ else sudo apt-get install -y lsb-release wget software-properties-common gnupg wget https://apt.llvm.org/llvm.sh - sudo bash llvm.sh $2 + sudo bash llvm.sh ${VERSION} sudo rm -f /usr/bin/clang sudo rm -f /usr/bin/clang++ @@ -33,4 +33,4 @@ else sudo ln -s $(which clang++-$VERSION) /usr/bin/clang++ clang --version -fi \ No newline at end of file +fi From c71070361957cc202d7c3c504797c5b3777bb956 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:52:53 -0400 Subject: [PATCH 081/371] Apply shell check --- devcontainer/install_compiler.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/devcontainer/install_compiler.sh b/devcontainer/install_compiler.sh index 7ebdafdc..ec53dec6 100644 --- a/devcontainer/install_compiler.sh +++ b/devcontainer/install_compiler.sh @@ -10,27 +10,27 @@ echo "Install ${TOOL} at: ${VERSION}" shopt -s nocasematch if [ "$TOOL" = "gnu" ]; then - sudo apt-get remove -y gcc-$VERSION g++-$VERSION gcc g++ - sudo apt-get install -y gcc-$VERSION g++-$VERSION + sudo apt-get remove -y gcc-"$VERSION" g++-"$VERSION" gcc g++ + sudo apt-get install -y gcc-"$VERSION" g++-"$VERSION" sudo rm -f /usr/bin/gcc sudo rm -f /usr/bin/g++ - sudo ln -s $(which gcc-$VERSION) /usr/bin/gcc - sudo ln -s $(which g++-$VERSION) /usr/bin/g++ + sudo ln -s "$(which gcc-"$VERSION")" /usr/bin/gcc + sudo ln -s "$(which g++-"$VERSION")" /usr/bin/g++ gcc --version else sudo apt-get install -y lsb-release wget software-properties-common gnupg wget https://apt.llvm.org/llvm.sh - sudo bash llvm.sh ${VERSION} + sudo bash llvm.sh "${VERSION}" sudo rm -f /usr/bin/clang sudo rm -f /usr/bin/clang++ - sudo ln -s $(which clang-$VERSION) /usr/bin/clang - sudo ln -s $(which clang++-$VERSION) /usr/bin/clang++ + sudo ln -s "$(which clang-"$VERSION")" /usr/bin/clang + sudo ln -s "$(which clang++-"$VERSION")" /usr/bin/clang++ clang --version fi From b3604696ee7855ffb6f2c3398405eb4656598e96 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:58:33 -0400 Subject: [PATCH 082/371] Install `libgtest` --- devcontainer/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devcontainer/Dockerfile b/devcontainer/Dockerfile index 1d6c7bea..f72e9944 100644 --- a/devcontainer/Dockerfile +++ b/devcontainer/Dockerfile @@ -22,6 +22,9 @@ ARG compiler_version=14 COPY install_compiler.sh . RUN bash install_compiler.sh ${compiler_kind} ${compiler_version} +# Needed for recent exemplar +RUN sudo apt-get install -y libgtest-dev + # Pre-commit is beman library's standard linting tool RUN sudo apt-get install -y pipx RUN pipx install pre-commit From b02eb224329929c0adc5eea8a96c7bb8beabfcfa Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 14 Mar 2025 19:22:29 -0400 Subject: [PATCH 083/371] Quick fix for `Compute Image Name` --- .github/workflows/build_devcontainer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index a003c32f..f538a671 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -28,13 +28,13 @@ jobs: version: 14 - kind: llvm version: 19 - name: Update devcontainer ${{ matrix.kind }}-${{ matrix.version }} + name: "devcontainer: ${{ matrix.kind }}-${{ matrix.version }}" steps: - name: Compute Image Name id: image_name run: | image_name=${{ env.DEPLOY_IMAGE_NAME }} - if [ "${{ github.repository }}/${{ github.ref }}" != "beman/infra/refs/heads/main" ]; then + if [ "${{ github.repository }}/${{ github.ref }}" != "bemanproject/infra/refs/heads/main" ]; then image_name=${{ env.DEBUG_IMAGE_NAME }} fi echo "computed image name: $image_name" From 4d7b01c8730fbca59ecbcdd2b804ec2a56e14b89 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Sun, 16 Mar 2025 12:05:46 -0400 Subject: [PATCH 084/371] CMake: Add -fsanitize-undefined-trap-on-error to MaxSan configuration Previously, the following implementation of identity would pass all tests under MaxSan: ``` struct identity { // Returns `t`. template constexpr T&& operator()(T&& t) const noexcept { int x = std::numeric_limits::max(); ++x; return std::forward(t); } using is_transparent = __is_transparent; }; ``` This is because UndefinedBehaviorSanitizer would diagnose the integer overflow by printing, but would not abort the program: ``` [ RUN ] IdentityTest.check_is_transparent bemanproject/exemplar/include/beman/exemplar/identity.hpp:37:7: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' [ OK ] IdentityTest.check_is_transparent (0 ms) ``` After this change, the test correctly fails, with SIGILL: ``` The following tests FAILED: 1 - IdentityTest.call_identity_with_int (ILLEGAL) ``` --- cmake/gnu-toolchain.cmake | 2 +- cmake/llvm-toolchain.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake index 2e2a2ad2..b6dddf6a 100644 --- a/cmake/gnu-toolchain.cmake +++ b/cmake/gnu-toolchain.cmake @@ -20,7 +20,7 @@ set(CMAKE_CXX_COMPILER g++) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS - "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined -fsanitize-undefined-trap-on-error" ) elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") set(SANITIZER_FLAGS "-fsanitize=thread") diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake index d783803b..5f5ee4b8 100644 --- a/cmake/llvm-toolchain.cmake +++ b/cmake/llvm-toolchain.cmake @@ -20,7 +20,7 @@ set(CMAKE_CXX_COMPILER clang++) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS - "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined" + "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined -fsanitize-undefined-trap-on-error" ) elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan") set(SANITIZER_FLAGS "-fsanitize=thread") From 90f6109ede8af7f93627b7666dd72ac27c63ac33 Mon Sep 17 00:00:00 2001 From: Bret Brown Date: Mon, 21 Apr 2025 10:45:16 -0400 Subject: [PATCH 085/371] Clean up install logic Problem ------- Using the parameters to describe the project in `project()` is misleading. It happens to be that the name `beman.exemplar` is used as the name of the project and as the CMake export name, but those are two different concepts that do not necessarily align. Also, the variable dereferencing in CMakeLists.txt is no less error prone than typing beman.exemplar. That's because it is not difficult to type things like ${PROJET_SOURCE_DIR}, which CMake will expand to an empty string. Instead, the readability of the install logic improves because it looks like a file with a specific name is being specifically created and referenced, which is the intention of the relevant installation logic. Solution -------- * Remove references to PROJECT_NAME, PROJECT_SOURCE_DIR, and PROJECT_BINARY_DIR. Prefer relative paths to CMAKE_CURRENT_SOUCE_DIR and CMAKE_CURRENT_BINARY_DIR instead. * Rename the install COMPONENT for beman.exemplar to "beman.exemplar" instead of "development". * Add the install COMPONENT to the installation of the beman.exemplar library target itself. * Move FetchContent include to use-fetch-content.cmake. --- cmake/beman.exemplar-config.cmake.in | 7 ------- cmake/use-fetch-content.cmake | 2 ++ 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 cmake/beman.exemplar-config.cmake.in diff --git a/cmake/beman.exemplar-config.cmake.in b/cmake/beman.exemplar-config.cmake.in deleted file mode 100644 index 5769cc3b..00000000 --- a/cmake/beman.exemplar-config.cmake.in +++ /dev/null @@ -1,7 +0,0 @@ -set(BEMAN_EXEMPLAR_VERSION @PROJECT_VERSION@) - -@PACKAGE_INIT@ - -include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake) - -check_required_components(@PROJECT_NAME@) diff --git a/cmake/use-fetch-content.cmake b/cmake/use-fetch-content.cmake index 63dc9c9b..a9130520 100644 --- a/cmake/use-fetch-content.cmake +++ b/cmake/use-fetch-content.cmake @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 3.24) +include(FetchContent) + if(NOT BEMAN_EXEMPLAR_LOCKFILE) set(BEMAN_EXEMPLAR_LOCKFILE "lockfile.json" From 8f3e4c59d9be06364fdce991669815c8c4eda1c3 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Tue, 29 Apr 2025 10:39:36 -0400 Subject: [PATCH 086/371] Formatting and spelling cleanups to pass the exemplar lint check --- README.md | 1 + devcontainer/Dockerfile | 2 +- devcontainer/README.md | 28 ++++++++++++++-------------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 20b85397..58da0f6b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # infra + Internal Beman Project infrastructure repo diff --git a/devcontainer/Dockerfile b/devcontainer/Dockerfile index f72e9944..313e1297 100644 --- a/devcontainer/Dockerfile +++ b/devcontainer/Dockerfile @@ -15,7 +15,7 @@ EOF # Newer gcc/ llvm is needed to avoid ASAN Stalling, which is turned on by default across beman projects. # See: https://github.com/google/sanitizers/issues/1614 -# Minimal vesion: clang-18.1.3, gcc-13.2 +# Minimal version: clang-18.1.3, gcc-13.2 ARG compiler_kind=gnu ARG compiler_version=14 diff --git a/devcontainer/README.md b/devcontainer/README.md index fbb20133..df60dc59 100644 --- a/devcontainer/README.md +++ b/devcontainer/README.md @@ -2,11 +2,11 @@ -This folder contains the infrastructure for Beman project's -generic devcontainer image. You can checkout available images in beman's +This folder contains the infrastructure for Beman project's +generic devcontainer image. You can checkout available images in beman's [GitHub Packages page](https://github.com/orgs/bemanproject/packages/container/package/devcontainers). -The image is build on top of GitHub's +The image is build on top of GitHub's [C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp) for Ubuntu 24.04. @@ -21,17 +21,17 @@ The image includes: ```json // SPDX-License-Identifier: 2.0 license with LLVM exceptions { - "name": "Beman Generic Devcontainer", - "image": "ghcr.io/bemanproject/devcontainers:gnu-14", - "postCreateCommand": "pre-commit", - "customizations": { - "vscode": { - "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cmake-tools" - ] - } - } + "name": "Beman Generic Devcontainer", + "image": "ghcr.io/bemanproject/devcontainers:gnu-14", + "postCreateCommand": "pre-commit", + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ] + } + } } ``` From 96c65868217f3c510def4c3d0483a429270733eb Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:14:41 -0400 Subject: [PATCH 087/371] Fix container namespace --- .github/workflows/build_devcontainer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index f538a671..811f874a 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -12,7 +12,7 @@ on: env: REGISTRY: ghcr.io DEBUG_IMAGE_NAME: ${{ github.repository }} - DEPLOY_IMAGE_NAME: beman/devcontainers + DEPLOY_IMAGE_NAME: bemanproject/devcontainers permissions: packages: write From 55e07504fd59f47bfb17d3c67a08f375b474ae45 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 20:39:23 +0000 Subject: [PATCH 088/371] lay way for testing container --- .github/workflows/build_devcontainer.yml | 27 ++++++++++++++----- {devcontainer => containers}/Dockerfile | 0 {devcontainer => containers}/README.md | 23 +++++++++------- .../install_compiler.sh | 0 4 files changed, 33 insertions(+), 17 deletions(-) rename {devcontainer => containers}/Dockerfile (100%) rename {devcontainer => containers}/README.md (83%) rename {devcontainer => containers}/install_compiler.sh (100%) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index f538a671..5852f938 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -12,13 +12,14 @@ on: env: REGISTRY: ghcr.io DEBUG_IMAGE_NAME: ${{ github.repository }} - DEPLOY_IMAGE_NAME: beman/devcontainers + DEPLOY_DEV_IMAGE_NAME: bemanproject/devcontainers + DEPLOY_TESTING_IMAGE_NAME: bemanproject/devcontainers permissions: packages: write jobs: - build-and-push-devcontainer-image: + devcontainers: runs-on: ubuntu-latest strategy: fail-fast: false @@ -26,19 +27,31 @@ jobs: include: - kind: gnu version: 14 + usage: dev - kind: llvm version: 19 - name: "devcontainer: ${{ matrix.kind }}-${{ matrix.version }}" + usage: dev + name: "${{ matrix.usage }}: ${{ matrix.kind }}-${{ matrix.version }}" steps: - name: Compute Image Name id: image_name run: | - image_name=${{ env.DEPLOY_IMAGE_NAME }} if [ "${{ github.repository }}/${{ github.ref }}" != "bemanproject/infra/refs/heads/main" ]; then - image_name=${{ env.DEBUG_IMAGE_NAME }} + image_name="${{ env.DEBUG_IMAGE_NAME }}" + tag="${{ matrix.usage }}-${{ matrix.kind }}-${{ matrix.version }}" + else + if [ "${{ matrix.usage }}" = "dev" ]; then + image_name="${{ env.DEPLOY_DEV_IMAGE_NAME }}" + else + image_name="${{ env.DEPLOY_TESTING_IMAGE_NAME }}" + fi + tag="${{ matrix.kind }}-${{ matrix.version }}" fi + echo "computed image name: $image_name" + echo "computed tag: $tag" echo "image_name=$image_name" >> "$GITHUB_OUTPUT" + echo "tag=$tag" >> "$GITHUB_OUTPUT" - name: Checkout repository uses: actions/checkout@v4 - name: Log in to the Container registry @@ -50,11 +63,11 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v6 with: - context: devcontainer + context: containers build-args: | compiler_kind=${{ matrix.kind }} compiler_version=${{ matrix.version }} push: true - tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:${{ matrix.kind }}-${{ matrix.version }} + tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:${{ steps.image_name.outputs.tag }} # https://github.com/docker/build-push-action/issues/894 provenance: false diff --git a/devcontainer/Dockerfile b/containers/Dockerfile similarity index 100% rename from devcontainer/Dockerfile rename to containers/Dockerfile diff --git a/devcontainer/README.md b/containers/README.md similarity index 83% rename from devcontainer/README.md rename to containers/README.md index df60dc59..3e30133c 100644 --- a/devcontainer/README.md +++ b/containers/README.md @@ -1,22 +1,25 @@ -# Devcontainer +# Containers This folder contains the infrastructure for Beman project's -generic devcontainer image. You can checkout available images in beman's -[GitHub Packages page](https://github.com/orgs/bemanproject/packages/container/package/devcontainers). +generic container images. You can checkout available images in beman's +[GitHub Packages page](https://github.com/orgs/bemanproject/packages). -The image is build on top of GitHub's -[C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp) -for Ubuntu 24.04. - -The image includes: +These images includes: - The latest CMake from kitware's apt repository - Latest compiler based on build args (gnu or llvm) installed from the universe repository - [pre-commit](https://pre-commit.com/), the standard linter manager across Beman -## Example devcontainer setup + +## Devcontainer + +The image is build on top of GitHub's +[C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp) +for Ubuntu 24.04. + +### Example devcontainer setup ```json // SPDX-License-Identifier: 2.0 license with LLVM exceptions @@ -35,7 +38,7 @@ The image includes: } ``` -## Building your own image +### Building your own image You can build your own Beman devcontainer image with: diff --git a/devcontainer/install_compiler.sh b/containers/install_compiler.sh similarity index 100% rename from devcontainer/install_compiler.sh rename to containers/install_compiler.sh From c1ed816d9289e16d07a8284d3cfcf7f4fa427e4e Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:02:33 +0000 Subject: [PATCH 089/371] add infra for test containers --- .github/workflows/build_devcontainer.yml | 13 ++++++++++++- containers/Dockerfile | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 5852f938..40338847 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -14,12 +14,14 @@ env: DEBUG_IMAGE_NAME: ${{ github.repository }} DEPLOY_DEV_IMAGE_NAME: bemanproject/devcontainers DEPLOY_TESTING_IMAGE_NAME: bemanproject/devcontainers + BASE_IMAGE_DEV: mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 + BASE_IMAGE_TEST: ubuntu:24.04 permissions: packages: write jobs: - devcontainers: + containers: runs-on: ubuntu-latest strategy: fail-fast: false @@ -52,6 +54,14 @@ jobs: echo "computed tag: $tag" echo "image_name=$image_name" >> "$GITHUB_OUTPUT" echo "tag=$tag" >> "$GITHUB_OUTPUT" + - name: Compute Image base + id: image_base + run: | + if [ "${{ matrix.usage }}" == "dev" ]; then + echo "image=${{ env.BASE_IMAGE_DEV }}" >> "$GITHUB_OUTPUT" + else + echo "image=${{ env.BASE_IMAGE_TEST }}" >> "$GITHUB_OUTPUT" + fi - name: Checkout repository uses: actions/checkout@v4 - name: Log in to the Container registry @@ -65,6 +75,7 @@ jobs: with: context: containers build-args: | + base_image=${{ steps.image_base.outputs.image }} compiler_kind=${{ matrix.kind }} compiler_version=${{ matrix.version }} push: true diff --git a/containers/Dockerfile b/containers/Dockerfile index 313e1297..18037278 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 +ARG base_image=mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 +FROM ${base_image} USER vscode WORKDIR /tmp From 8ef5a0d7b233478ead642f4905bdeef6fa59d1e7 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:05:23 +0000 Subject: [PATCH 090/371] add a test container --- .github/workflows/build_devcontainer.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 40338847..fdbfd47d 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -13,7 +13,7 @@ env: REGISTRY: ghcr.io DEBUG_IMAGE_NAME: ${{ github.repository }} DEPLOY_DEV_IMAGE_NAME: bemanproject/devcontainers - DEPLOY_TESTING_IMAGE_NAME: bemanproject/devcontainers + DEPLOY_TESTING_IMAGE_NAME: bemanproject/testing-images BASE_IMAGE_DEV: mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 BASE_IMAGE_TEST: ubuntu:24.04 @@ -33,6 +33,9 @@ jobs: - kind: llvm version: 19 usage: dev + - kind: gnu + version: 14 + usage: test name: "${{ matrix.usage }}: ${{ matrix.kind }}-${{ matrix.version }}" steps: - name: Compute Image Name @@ -49,9 +52,6 @@ jobs: fi tag="${{ matrix.kind }}-${{ matrix.version }}" fi - - echo "computed image name: $image_name" - echo "computed tag: $tag" echo "image_name=$image_name" >> "$GITHUB_OUTPUT" echo "tag=$tag" >> "$GITHUB_OUTPUT" - name: Compute Image base From c6c2167ddc0b38c1bc38f7854c9e51803bb69d41 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:11:22 +0000 Subject: [PATCH 091/371] create vscode user if not exist --- containers/Dockerfile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/containers/Dockerfile b/containers/Dockerfile index 18037278..63fb1e0d 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -3,6 +3,14 @@ ARG base_image=mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 FROM ${base_image} +# Create the vscode user +RUN bash </dev/null; then + sudo useradd -m -s /bin/bash vscode + sudo usermod -aG sudo vscode + fi +EOF + USER vscode WORKDIR /tmp From d0f0b82b1a95632d3af1859adf82c6940559f692 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:12:20 +0000 Subject: [PATCH 092/371] update paths --- .github/workflows/build_devcontainer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index fdbfd47d..969bebe7 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -6,7 +6,7 @@ on: push: paths: - ".github/workflows/build_devcontainer.yml" - - "devcontainer/**" + - "containers/**" workflow_dispatch: env: From cb8c17b7008cd59474ca7fe970003eaa9c731bd4 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:19:19 +0000 Subject: [PATCH 093/371] Fix docker --- containers/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/containers/Dockerfile b/containers/Dockerfile index 63fb1e0d..a677040e 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -6,8 +6,8 @@ FROM ${base_image} # Create the vscode user RUN bash </dev/null; then - sudo useradd -m -s /bin/bash vscode - sudo usermod -aG sudo vscode + apt-get update && apt-get install -y sudo adduser + useradd -ms /bin/bash -p "" vscode && usermod -aG sudo vscode fi EOF @@ -31,7 +31,7 @@ ARG compiler_version=14 COPY install_compiler.sh . RUN bash install_compiler.sh ${compiler_kind} ${compiler_version} -# Needed for recent exemplar +# Common dependency: google-test RUN sudo apt-get install -y libgtest-dev # Pre-commit is beman library's standard linting tool From 2ca07e025f31cbbe03e687d16ff7dc30ff7a2287 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:20:55 +0000 Subject: [PATCH 094/371] install gpg --- containers/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/containers/Dockerfile b/containers/Dockerfile index a677040e..ffebd77f 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -17,6 +17,7 @@ WORKDIR /tmp # Latest CMake needed for most of the beman libraries, # so we need to install via kitware's apt repo RUN bash </dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null sudo apt-get update && sudo apt-get install -y cmake From e5f7f5fbc8b8407f24a94cdb3aca67538b610506 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:23:49 +0000 Subject: [PATCH 095/371] update matrix --- .github/workflows/build_devcontainer.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 969bebe7..ffc01ae1 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -26,31 +26,27 @@ jobs: strategy: fail-fast: false matrix: - include: + compilers: - kind: gnu version: 14 - usage: dev - kind: llvm version: 19 - usage: dev - - kind: gnu - version: 14 - usage: test - name: "${{ matrix.usage }}: ${{ matrix.kind }}-${{ matrix.version }}" + usage: [dev, test] + name: "${{ matrix.usage }}: ${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" steps: - name: Compute Image Name id: image_name run: | if [ "${{ github.repository }}/${{ github.ref }}" != "bemanproject/infra/refs/heads/main" ]; then image_name="${{ env.DEBUG_IMAGE_NAME }}" - tag="${{ matrix.usage }}-${{ matrix.kind }}-${{ matrix.version }}" + tag="${{ matrix.usage }}-${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" else if [ "${{ matrix.usage }}" = "dev" ]; then image_name="${{ env.DEPLOY_DEV_IMAGE_NAME }}" else image_name="${{ env.DEPLOY_TESTING_IMAGE_NAME }}" fi - tag="${{ matrix.kind }}-${{ matrix.version }}" + tag="${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" fi echo "image_name=$image_name" >> "$GITHUB_OUTPUT" echo "tag=$tag" >> "$GITHUB_OUTPUT" @@ -76,8 +72,8 @@ jobs: context: containers build-args: | base_image=${{ steps.image_base.outputs.image }} - compiler_kind=${{ matrix.kind }} - compiler_version=${{ matrix.version }} + compiler_kind=${{ matrix.compilers.kind }} + compiler_version=${{ matrix.compilers.version }} push: true tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:${{ steps.image_name.outputs.tag }} # https://github.com/docker/build-push-action/issues/894 From 63a9ea50eb07b21edb60b76943eb98ed6c69cc3b Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:29:59 +0000 Subject: [PATCH 096/371] Add more basic utilities --- containers/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/containers/Dockerfile b/containers/Dockerfile index ffebd77f..b5b7dbb9 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -14,10 +14,11 @@ EOF USER vscode WORKDIR /tmp +# Install basic utilities and CMake. # Latest CMake needed for most of the beman libraries, # so we need to install via kitware's apt repo RUN bash </dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null sudo apt-get update && sudo apt-get install -y cmake From c4a21172433a1cf4eb58eb8c7d8dc56c57950901 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:33:17 +0000 Subject: [PATCH 097/371] Add more gnu versions --- .github/workflows/build_devcontainer.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index ffc01ae1..d49055eb 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -27,8 +27,14 @@ jobs: fail-fast: false matrix: compilers: + - kind: gnu + version: 15 - kind: gnu version: 14 + - kind: gnu + version: 13 + - kind: gnu + version: 12 - kind: llvm version: 19 usage: [dev, test] From f88c899a1657d352c8d9d1433caff9c5b2b65d2a Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:45:52 +0000 Subject: [PATCH 098/371] constrain to latest 4 gnu versions --- .github/workflows/build_devcontainer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index d49055eb..1ddd4e5a 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -27,14 +27,14 @@ jobs: fail-fast: false matrix: compilers: - - kind: gnu - version: 15 - kind: gnu version: 14 - kind: gnu version: 13 - kind: gnu version: 12 + - kind: gnu + version: 11 - kind: llvm version: 19 usage: [dev, test] From 40b774b11ce64a2b9765f37886949fcecb338f44 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:48:56 +0000 Subject: [PATCH 099/371] more llvm versions --- .github/workflows/build_devcontainer.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 1ddd4e5a..afc762ae 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -35,8 +35,14 @@ jobs: version: 12 - kind: gnu version: 11 + - kind: llvm + version: 20 - kind: llvm version: 19 + - kind: llvm + version: 18 + - kind: llvm + version: 17 usage: [dev, test] name: "${{ matrix.usage }}: ${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" steps: From 94cdc3318018fc707ac0914d79196d97849a798d Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:54:04 +0000 Subject: [PATCH 100/371] Update CI workflow name --- .github/workflows/build_devcontainer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index afc762ae..4d914631 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: 2.0 license with LLVM exceptions -name: Publish Beman devcontainers +name: Publish Beman Containers on: push: From 2be898ee91cb18a504fef6a307405b57db2a612d Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:35:38 +0000 Subject: [PATCH 101/371] add ninja build --- containers/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/containers/Dockerfile b/containers/Dockerfile index b5b7dbb9..5d69029d 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -14,7 +14,7 @@ EOF USER vscode WORKDIR /tmp -# Install basic utilities and CMake. +# Install basic utilities, CMake and Ninja. # Latest CMake needed for most of the beman libraries, # so we need to install via kitware's apt repo RUN bash </dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null sudo apt-get update && sudo apt-get install -y cmake + + sudo apt-get install -y ninja-build EOF # Newer gcc/ llvm is needed to avoid ASAN Stalling, which is turned on by default across beman projects. From 1fd43cc88273eb09856d8437c5f45fe3d9fb99a3 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:42:47 +0000 Subject: [PATCH 102/371] add libc++ --- containers/install_compiler.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index ec53dec6..1c097e7a 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -34,3 +34,6 @@ else clang --version fi + +# Install libc++ +sudo apt-get install libc++-dev libc++abi-dev From 2b0467fe907adabfb09e488a0cbadce6e12a7eb1 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:48:49 +0000 Subject: [PATCH 103/371] fix install --- containers/install_compiler.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index 1c097e7a..4642cb30 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -36,4 +36,4 @@ else fi # Install libc++ -sudo apt-get install libc++-dev libc++abi-dev +sudo apt-get install -y libc++-dev libc++abi-dev From e7976101cb07c7918444f0269db339b7c72c7a6f Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 2 May 2025 20:48:07 +0000 Subject: [PATCH 104/371] refactor installation --- containers/Dockerfile | 13 ++----------- containers/install_sys.sh | 10 ++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 containers/install_sys.sh diff --git a/containers/Dockerfile b/containers/Dockerfile index 5d69029d..74bd6cbb 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -14,17 +14,8 @@ EOF USER vscode WORKDIR /tmp -# Install basic utilities, CMake and Ninja. -# Latest CMake needed for most of the beman libraries, -# so we need to install via kitware's apt repo -RUN bash </dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null - echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null - sudo apt-get update && sudo apt-get install -y cmake - - sudo apt-get install -y ninja-build -EOF +COPY install_sys.sh . +RUN bash install_sys.sh # Newer gcc/ llvm is needed to avoid ASAN Stalling, which is turned on by default across beman projects. # See: https://github.com/google/sanitizers/issues/1614 diff --git a/containers/install_sys.sh b/containers/install_sys.sh new file mode 100644 index 00000000..272ab7bf --- /dev/null +++ b/containers/install_sys.sh @@ -0,0 +1,10 @@ +# Install Basic utilities +sudo apt-get install -y ca-certificates gpg wget git curl + +# Install Latest CMake +wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null +echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null +sudo apt-get update && sudo apt-get install -y cmake + +# Install Ninja +sudo apt-get install -y ninja-build \ No newline at end of file From 08cdb4cb27b5df4508835699b25913b7210dbda7 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Fri, 2 May 2025 20:49:28 +0000 Subject: [PATCH 105/371] specify libc --- containers/install_compiler.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index 4642cb30..c76f0b3f 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -25,6 +25,7 @@ else wget https://apt.llvm.org/llvm.sh sudo bash llvm.sh "${VERSION}" + sudo apt-get install -y libc++-"$VERSION"-dev sudo rm -f /usr/bin/clang sudo rm -f /usr/bin/clang++ @@ -35,5 +36,3 @@ else clang --version fi -# Install libc++ -sudo apt-get install -y libc++-dev libc++abi-dev From d9edce374839b5d8adf2fa200e67be0b8ff86567 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 5 May 2025 17:48:41 -0400 Subject: [PATCH 106/371] Fix SPDX-License-Identifiers "2.0 license with LLVM exceptions" seems to be a typo for "Apache-2.0 WITH LLVM-exception". --- .github/workflows/build_devcontainer.yml | 2 +- devcontainer/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 811f874a..5de39eda 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception name: Publish Beman devcontainers diff --git a/devcontainer/README.md b/devcontainer/README.md index df60dc59..d6e632f3 100644 --- a/devcontainer/README.md +++ b/devcontainer/README.md @@ -1,6 +1,6 @@ # Devcontainer - + This folder contains the infrastructure for Beman project's generic devcontainer image. You can checkout available images in beman's @@ -19,7 +19,7 @@ The image includes: ## Example devcontainer setup ```json -// SPDX-License-Identifier: 2.0 license with LLVM exceptions +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception { "name": "Beman Generic Devcontainer", "image": "ghcr.io/bemanproject/devcontainers:gnu-14", From c220329fbe66d0bc385b731a487dc45f19ac96eb Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 7 May 2025 01:24:33 +0000 Subject: [PATCH 107/371] Link gcov --- containers/install_compiler.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index c76f0b3f..eefcab4d 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -18,6 +18,7 @@ if [ "$TOOL" = "gnu" ]; then sudo ln -s "$(which gcc-"$VERSION")" /usr/bin/gcc sudo ln -s "$(which g++-"$VERSION")" /usr/bin/g++ + sudo ln -s "$(which gcov-"$VERSION")" /usr/bin/gcov gcc --version else From eba0af77967ff67844928497c69e77e93fff6bad Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 7 May 2025 18:03:12 +0000 Subject: [PATCH 108/371] Add coverage tool --- containers/install_compiler.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index eefcab4d..bff95319 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -8,6 +8,9 @@ VERSION=$2 echo "Install ${TOOL} at: ${VERSION}" +# Install coverage tools +sudo apt-get install -y lcov + shopt -s nocasematch if [ "$TOOL" = "gnu" ]; then sudo apt-get remove -y gcc-"$VERSION" g++-"$VERSION" gcc g++ From dc9451985e7057c57173c54d55320a948bc8a803 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 7 May 2025 18:15:13 +0000 Subject: [PATCH 109/371] move lcov install to after compiler --- containers/install_compiler.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index bff95319..f5c420f4 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -8,13 +8,10 @@ VERSION=$2 echo "Install ${TOOL} at: ${VERSION}" -# Install coverage tools -sudo apt-get install -y lcov - shopt -s nocasematch if [ "$TOOL" = "gnu" ]; then sudo apt-get remove -y gcc-"$VERSION" g++-"$VERSION" gcc g++ - sudo apt-get install -y gcc-"$VERSION" g++-"$VERSION" + sudo apt-get install -y gcc-"$VERSION" g++-"$VERSION" lcov sudo rm -f /usr/bin/gcc sudo rm -f /usr/bin/g++ @@ -29,7 +26,7 @@ else wget https://apt.llvm.org/llvm.sh sudo bash llvm.sh "${VERSION}" - sudo apt-get install -y libc++-"$VERSION"-dev + sudo apt-get install -y libc++-"$VERSION"-dev lcov sudo rm -f /usr/bin/clang sudo rm -f /usr/bin/clang++ From 4fbaae2e6ee64e8c28c3315e9232da6831e7544a Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 7 May 2025 18:16:37 +0000 Subject: [PATCH 110/371] remove gcov link --- containers/install_compiler.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index f5c420f4..6f684beb 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -18,7 +18,6 @@ if [ "$TOOL" = "gnu" ]; then sudo ln -s "$(which gcc-"$VERSION")" /usr/bin/gcc sudo ln -s "$(which g++-"$VERSION")" /usr/bin/g++ - sudo ln -s "$(which gcov-"$VERSION")" /usr/bin/gcov gcc --version else From 4436d2a421b7e63227ae0d4a21eeaf03e1678d86 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 7 May 2025 18:21:15 +0000 Subject: [PATCH 111/371] relink gcov --- containers/install_compiler.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index 6f684beb..b90a6f8b 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -15,9 +15,11 @@ if [ "$TOOL" = "gnu" ]; then sudo rm -f /usr/bin/gcc sudo rm -f /usr/bin/g++ + sudo rm -f /usr/bin/gcov sudo ln -s "$(which gcc-"$VERSION")" /usr/bin/gcc sudo ln -s "$(which g++-"$VERSION")" /usr/bin/g++ + sudo ln -s "$(which gcov-"$VERSION")" /usr/bin/gcov gcc --version else From cefbbc04b803ab98d14b9ff133b1dd79ea13bf4e Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Wed, 7 May 2025 18:45:28 +0000 Subject: [PATCH 112/371] Add llvm 21 --- .github/workflows/build_devcontainer.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 4d914631..01942d74 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -35,6 +35,8 @@ jobs: version: 12 - kind: gnu version: 11 + - kind: llvm + version: 21 - kind: llvm version: 20 - kind: llvm From d3a96a0400ba3e09fa73a6a4be71612aa72b7234 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 10 May 2025 22:07:22 +0000 Subject: [PATCH 113/371] change naming for gnu, llvm --- .github/workflows/build_devcontainer.yml | 18 +++++++++--------- containers/Dockerfile | 4 ++-- containers/README.md | 4 ++-- containers/install_compiler.sh | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 01942d74..59b4d784 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -27,23 +27,23 @@ jobs: fail-fast: false matrix: compilers: - - kind: gnu + - kind: gcc version: 14 - - kind: gnu + - kind: gcc version: 13 - - kind: gnu + - kind: gcc version: 12 - - kind: gnu + - kind: gcc version: 11 - - kind: llvm + - kind: clang version: 21 - - kind: llvm + - kind: clang version: 20 - - kind: llvm + - kind: clang version: 19 - - kind: llvm + - kind: clang version: 18 - - kind: llvm + - kind: clang version: 17 usage: [dev, test] name: "${{ matrix.usage }}: ${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" diff --git a/containers/Dockerfile b/containers/Dockerfile index 74bd6cbb..f5f5f9d0 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -17,10 +17,10 @@ WORKDIR /tmp COPY install_sys.sh . RUN bash install_sys.sh -# Newer gcc/ llvm is needed to avoid ASAN Stalling, which is turned on by default across beman projects. +# Newer gcc/ clang is needed to avoid ASAN Stalling, which is turned on by default across beman projects. # See: https://github.com/google/sanitizers/issues/1614 # Minimal version: clang-18.1.3, gcc-13.2 -ARG compiler_kind=gnu +ARG compiler_kind=gcc ARG compiler_version=14 COPY install_compiler.sh . diff --git a/containers/README.md b/containers/README.md index 3e30133c..8a9e7fc9 100644 --- a/containers/README.md +++ b/containers/README.md @@ -9,7 +9,7 @@ generic container images. You can checkout available images in beman's These images includes: - The latest CMake from kitware's apt repository -- Latest compiler based on build args (gnu or llvm) installed from the universe repository +- Latest compiler based on build args (gcc or clang) installed from the universe repository - [pre-commit](https://pre-commit.com/), the standard linter manager across Beman @@ -25,7 +25,7 @@ for Ubuntu 24.04. // SPDX-License-Identifier: 2.0 license with LLVM exceptions { "name": "Beman Generic Devcontainer", - "image": "ghcr.io/bemanproject/devcontainers:gnu-14", + "image": "ghcr.io/bemanproject/devcontainers:gcc-14", "postCreateCommand": "pre-commit", "customizations": { "vscode": { diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index b90a6f8b..1cd77974 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -9,7 +9,7 @@ VERSION=$2 echo "Install ${TOOL} at: ${VERSION}" shopt -s nocasematch -if [ "$TOOL" = "gnu" ]; then +if [ "$TOOL" = "gcc" ]; then sudo apt-get remove -y gcc-"$VERSION" g++-"$VERSION" gcc g++ sudo apt-get install -y gcc-"$VERSION" g++-"$VERSION" lcov @@ -23,7 +23,7 @@ if [ "$TOOL" = "gnu" ]; then gcc --version else - sudo apt-get install -y lsb-release wget software-properties-common gnupg + sudo apt-get install -y lsb-release wget software-properties-common gccpg wget https://apt.llvm.org/llvm.sh sudo bash llvm.sh "${VERSION}" From 8d724196938a8c58bab70131f16b7ce6858fa3dd Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 10 May 2025 22:11:35 +0000 Subject: [PATCH 114/371] gccpg -> gnupg --- containers/install_compiler.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index 1cd77974..d2f96cca 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -23,7 +23,7 @@ if [ "$TOOL" = "gcc" ]; then gcc --version else - sudo apt-get install -y lsb-release wget software-properties-common gccpg + sudo apt-get install -y lsb-release wget software-properties-common gnupg wget https://apt.llvm.org/llvm.sh sudo bash llvm.sh "${VERSION}" From 9b69c4345628a9d1bf596e171f947b46ef3ea777 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 10 May 2025 22:22:50 +0000 Subject: [PATCH 115/371] update naming script --- .github/workflows/build_devcontainer.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml index 59b4d784..be464062 100644 --- a/.github/workflows/build_devcontainer.yml +++ b/.github/workflows/build_devcontainer.yml @@ -11,9 +11,9 @@ on: env: REGISTRY: ghcr.io - DEBUG_IMAGE_NAME: ${{ github.repository }} - DEPLOY_DEV_IMAGE_NAME: bemanproject/devcontainers - DEPLOY_TESTING_IMAGE_NAME: bemanproject/testing-images + DEBUG_NAME: ${{ github.repository }} + DEPLOY_DEV_NAME_PREFIX: bemanproject/devcontainers + DEPLOY_TESTING_NAME_PREFIX: bemanproject/testingcontainers BASE_IMAGE_DEV: mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 BASE_IMAGE_TEST: ubuntu:24.04 @@ -52,16 +52,19 @@ jobs: id: image_name run: | if [ "${{ github.repository }}/${{ github.ref }}" != "bemanproject/infra/refs/heads/main" ]; then - image_name="${{ env.DEBUG_IMAGE_NAME }}" + image_name="${{ env.DEBUG_NAME }}" tag="${{ matrix.usage }}-${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" else if [ "${{ matrix.usage }}" = "dev" ]; then - image_name="${{ env.DEPLOY_DEV_IMAGE_NAME }}" + image_name="${{ env.DEPLOY_DEV_NAME_PREFIX }}-${{ matrix.compilers.kind }}" else - image_name="${{ env.DEPLOY_TESTING_IMAGE_NAME }}" + image_name="${{ env.DEPLOY_TESTING_NAME_PREFIX }}-${{ matrix.compilers.kind }}" fi - tag="${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" + tag="${{ matrix.compilers.version }}" fi + + echo "Image Name: $image_name, Tag: $tag" + echo "image_name=$image_name" >> "$GITHUB_OUTPUT" echo "tag=$tag" >> "$GITHUB_OUTPUT" - name: Compute Image base From 6e3a3d3310077a5b7b02e2fa03b4b51a63456502 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Sat, 10 May 2025 21:10:16 -0400 Subject: [PATCH 116/371] Update docs --- containers/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/README.md b/containers/README.md index 8a9e7fc9..e16131bd 100644 --- a/containers/README.md +++ b/containers/README.md @@ -25,7 +25,7 @@ for Ubuntu 24.04. // SPDX-License-Identifier: 2.0 license with LLVM exceptions { "name": "Beman Generic Devcontainer", - "image": "ghcr.io/bemanproject/devcontainers:gcc-14", + "image": "ghcr.io/bemanproject/devcontainers-gcc:14", "postCreateCommand": "pre-commit", "customizations": { "vscode": { From ed1d100df0f43b0692a496c5e13e80624c4fecd0 Mon Sep 17 00:00:00 2001 From: Vito Gamberini Date: Mon, 2 Jun 2025 13:27:20 -0400 Subject: [PATCH 117/371] grab clang tools from upstream llvm --- containers/install_compiler.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh index d2f96cca..bef0e1c4 100644 --- a/containers/install_compiler.sh +++ b/containers/install_compiler.sh @@ -27,7 +27,7 @@ else wget https://apt.llvm.org/llvm.sh sudo bash llvm.sh "${VERSION}" - sudo apt-get install -y libc++-"$VERSION"-dev lcov + sudo apt-get install -y libc++-"$VERSION"-dev clang-tools-"$VERSION" lcov sudo rm -f /usr/bin/clang sudo rm -f /usr/bin/clang++ @@ -37,4 +37,3 @@ else clang --version fi - From 22c4122528eea0fb67f6c3012c682cf8835ceba2 Mon Sep 17 00:00:00 2001 From: Vito Gamberini Date: Tue, 3 Jun 2025 14:02:36 -0400 Subject: [PATCH 118/371] Invoke AppleClang via system compiler shims Fixes #171 --- cmake/appleclang-toolchain.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/appleclang-toolchain.cmake b/cmake/appleclang-toolchain.cmake index bc12103d..5f44e802 100644 --- a/cmake/appleclang-toolchain.cmake +++ b/cmake/appleclang-toolchain.cmake @@ -16,8 +16,10 @@ include_guard(GLOBAL) -set(CMAKE_C_COMPILER clang) -set(CMAKE_CXX_COMPILER clang++) +# Prevent PATH collision with an LLVM clang installation by using the system +# compiler shims +set(CMAKE_C_COMPILER cc) +set(CMAKE_CXX_COMPILER c++) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS From b2249639cb774672d631310f958d66853c0d1a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:04:56 +0300 Subject: [PATCH 119/371] Apply Beman Standard recommended license - LICENSE.APACHE_LLVM --- LICENSE | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..111a208f --- /dev/null +++ b/LICENSE @@ -0,0 +1,230 @@ + 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. + +============================================================================== +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. From 2dd4bdbe0ce635641aedaa0aba85a40ae082c497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:05:18 +0300 Subject: [PATCH 120/371] Add basic MD linter config --- .markdownlint.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .markdownlint.yaml diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..81f5fcd7 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,9 @@ +# MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md033.md +# Disable inline html linter is needed for
+MD033: false + +# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md013.md +# Conforms to .clang-format ColumnLimit +# Update the comment in .clang-format if we no-longer tie these two column limits. +MD013: + line_length: 119 From f575b884cde21237f6d1cd0ef2d00b48a3f01e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:05:32 +0300 Subject: [PATCH 121/371] Add basic docs --- README.md | 12 ++++++++++-- containers/README.md | 1 - 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 58da0f6b..4d31a49b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ -# infra +# Beman Project Infrastructure Repository -Internal Beman Project infrastructure repo + + +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 + +* `containers/`: Containers used for CI builds and tests in the Beman org. +* `tools/`: Tools used to manage the infrastructure and the codebase (e.g., linting, formatting, etc.). diff --git a/containers/README.md b/containers/README.md index d85f6ec8..83b357df 100644 --- a/containers/README.md +++ b/containers/README.md @@ -12,7 +12,6 @@ These images includes: - Latest compiler based on build args (gcc or clang) installed from the universe repository - [pre-commit](https://pre-commit.com/), the standard linter manager across Beman - ## Devcontainer The image is build on top of GitHub's From cfc96acad402f3f458e575bbb01b63fc8882c0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:13:24 +0300 Subject: [PATCH 122/371] Fix SPDX identifier --- tools/beman-tidy/README.md | 2 +- tools/beman-tidy/beman-tidy | 2 +- tools/beman-tidy/lib/checks/base/base_check.py | 2 +- tools/beman-tidy/lib/checks/base/generic_file_check.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/changelog.py | 4 ++-- tools/beman-tidy/lib/checks/beman_standard/cmake.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/cpp.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/directory.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/file.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/general.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/license.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/readme.py | 2 +- tools/beman-tidy/lib/checks/beman_standard/toplevel.py | 2 +- tools/beman-tidy/lib/checks/system/git.py | 2 +- tools/beman-tidy/lib/pipeline.py | 2 +- tools/beman-tidy/lib/utils/git.py | 2 +- tools/beman-tidy/lib/utils/string.py | 2 +- tools/beman-tidy/lib/utils/terminal.py | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 1f2bdba8..e71aa5c1 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -1,7 +1,7 @@ # beman-tidy: Codebase Bemanification Tool ## Description diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 5ba65f6b..7bbf4a05 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse from lib.utils.git import * diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 20ddc6f2..5e033516 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import os import sys diff --git a/tools/beman-tidy/lib/checks/base/generic_file_check.py b/tools/beman-tidy/lib/checks/base/generic_file_check.py index 0e831b4c..71f49685 100644 --- a/tools/beman-tidy/lib/checks/base/generic_file_check.py +++ b/tools/beman-tidy/lib/checks/base/generic_file_check.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .base_check import BSCheck import os diff --git a/tools/beman-tidy/lib/checks/beman_standard/changelog.py b/tools/beman-tidy/lib/checks/beman_standard/changelog.py index cbf3f45f..38efa7f2 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/changelog.py +++ b/tools/beman-tidy/lib/checks/beman_standard/changelog.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.generic_file_check import BSGenericFileCheck @@ -94,7 +94,7 @@ def fix(self): "# Changelog", "", "", "", "## [Unreleased]", diff --git a/tools/beman-tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/lib/checks/beman_standard/cmake.py index faa75763..491648f1 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cmake.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cmake.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO CMAKE.DEFAULT # TODO CMAKE.USE_FETCH_CONTENT diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/lib/checks/beman_standard/cpp.py index 2f10a19d..cbded5c4 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cpp.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cpp.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO CPP.NAMESPACE # TODO CPP.NO_FLAG_FORKING diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/lib/checks/beman_standard/directory.py index ed0638db..2e730d90 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/lib/checks/beman_standard/directory.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO DIRECTORY.INTERFACE_HEADERS # TODO DIRECTORY.IMPLEMENTATION_HEADERS diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/lib/checks/beman_standard/file.py index 366047f1..4e79f473 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/file.py +++ b/tools/beman-tidy/lib/checks/beman_standard/file.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO FILE.NAMES # TODO FILE.TEST_NAMES diff --git a/tools/beman-tidy/lib/checks/beman_standard/general.py b/tools/beman-tidy/lib/checks/beman_standard/general.py index 30d9f373..87cd7496 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/general.py +++ b/tools/beman-tidy/lib/checks/beman_standard/general.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO LIBRARY.NAMES # TODO REPOSITORY.NAME diff --git a/tools/beman-tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/lib/checks/beman_standard/license.py index 04254596..46b26ea2 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/lib/checks/beman_standard/license.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO LICENSE.APPROVED # TODO LICENSE.APACHE_LLVM diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index f63f19a5..a143b1e3 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.generic_file_check import BSGenericFileCheck from ...utils.string import * diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 30062a28..045308b7 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.generic_file_check import BSGenericFileCheck from ...utils.git import * diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index cbeb03f1..4380f921 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.base_check import BSCheck diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 926035be..f9d552b3 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .checks.system.git import * from .checks.beman_standard.changelog import * diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 5c455467..057ad4f7 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .terminal import run_command import markdown diff --git a/tools/beman-tidy/lib/utils/string.py b/tools/beman-tidy/lib/utils/string.py index b2772b14..770aa493 100644 --- a/tools/beman-tidy/lib/utils/string.py +++ b/tools/beman-tidy/lib/utils/string.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .git import download_beman_default_license import re diff --git a/tools/beman-tidy/lib/utils/terminal.py b/tools/beman-tidy/lib/utils/terminal.py index 619bfab6..b3fe87ae 100644 --- a/tools/beman-tidy/lib/utils/terminal.py +++ b/tools/beman-tidy/lib/utils/terminal.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# SPDX-License-Identifier: 2.0 license with LLVM exceptions +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import subprocess From 39d8243743a55c61091b7ebc9ff05dff8b0dba55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:26:11 +0300 Subject: [PATCH 123/371] Remove unused import --- tools/beman-tidy/beman-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 7bbf4a05..4d94f7c7 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,7 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse -from lib.utils.git import * from lib.pipeline import * def parse_args(): From 4d43d1695d40fecdc132f03f8109e7505a3fb70c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:29:52 +0300 Subject: [PATCH 124/371] beman-tidy: tweaks in docs --- tools/beman-tidy/beman-tidy | 5 +++-- tools/beman-tidy/lib/utils/git.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 4d94f7c7..01248bd3 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,11 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse +from lib.utils.git import * from lib.pipeline import * def parse_args(): """ - Parse the command line arguments. + Parse the CLI arguments. """ parser = argparse.ArgumentParser() @@ -27,7 +28,7 @@ def parse_args(): def main(): """ - beman-tidy main entry point. + The beman-tidy main entry point. """ args = parse_args() diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 057ad4f7..67cb916d 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -13,8 +13,8 @@ def get_repo_info(path): """ - Get information about the Git repository at the given path. - Returns a dictionary with data about the repository. + Get information about the repository at the given path. + Returns data as a dictionary. """ try: From 10ad08a6338328fae70ab03376d90c273a929d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:34:02 +0300 Subject: [PATCH 125/371] beman-tidy: tweaks in docs --- tools/beman-tidy/lib/checks/base/base_check.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 5e033516..bd81142e 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -7,12 +7,12 @@ class BSCheck(object): """ - Base class for all Beman Standard checks. + Base class for Beman Standard check (rule). """ def __init__(self, repo_info, beman_standard, check_name): """ - Initialize the check. + Create a new check instance. """ # check name e.g. "LIBRARY.NAMES" self.name = check_name @@ -68,17 +68,17 @@ def base_check(self): def check(self): """ - Checks if the Beman Standard check/rule is already applied. - - If the standard is applied, the check should return True. - - If the standard is not applied, the check should return False and self.fix() should be able to fix the issue. + 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. """ raise NotImplementedError(f"[{self.name}] check() not implemented.") def fix(self): """ - Fixes the issue if The Beman Standard is not applied. - - If the standard is applied, the check should return True. NOP here. - - - Otherwise, the check should be applied inplace. If the check cannot be applied inplace, the check should return False. + 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. """ return False From d42fc1f7a871b48fab2ac63509911b3b0af77039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:40:07 +0300 Subject: [PATCH 126/371] beman-tidy: tweaks in naming for base classes --- tools/beman-tidy/lib/checks/base/base_check.py | 4 ++-- ...eneric_file_check.py => file_base_check.py} | 10 +++++----- .../lib/checks/beman_standard/changelog.py | 4 ++-- .../lib/checks/beman_standard/readme.py | 4 ++-- .../lib/checks/beman_standard/toplevel.py | 18 +++++++++--------- tools/beman-tidy/lib/checks/system/git.py | 4 ++-- tools/beman-tidy/lib/pipeline.py | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) rename tools/beman-tidy/lib/checks/base/{generic_file_check.py => file_base_check.py} (90%) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index bd81142e..f62e74e6 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -5,7 +5,7 @@ import sys -class BSCheck(object): +class BaseCheck(object): """ Base class for Beman Standard check (rule). """ @@ -48,7 +48,7 @@ def __init__(self, repo_info, beman_standard, check_name): self.library_name = f"beman.{self.repo_name}" assert self.library_name is not None - def base_check(self): + def default_check(self): """ Checks if this rule is properly initialized. """ diff --git a/tools/beman-tidy/lib/checks/base/generic_file_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py similarity index 90% rename from tools/beman-tidy/lib/checks/base/generic_file_check.py rename to tools/beman-tidy/lib/checks/base/file_base_check.py index 71f49685..c932f1fa 100644 --- a/tools/beman-tidy/lib/checks/base/generic_file_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -1,14 +1,14 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from .base_check import BSCheck +from .base_check import BaseCheck import os import sys -class BSGenericFileCheck(BSCheck): +class FileBaseCheck(BaseCheck): """ - Base class for all Beman Standard checks. + Base class for all Beman Standard checks that operate on a file. """ def __init__(self, repo_info, beman_standard, check_name, relative_path): @@ -16,11 +16,11 @@ def __init__(self, repo_info, beman_standard, check_name, relative_path): self.path = os.path.join(repo_info["top_level"], relative_path) - def base_check(self): + def default_check(self): """ Checks if this rule is properly initialized. """ - if not super().base_check(): + if not super().default_check(): return False if self.path is None: diff --git a/tools/beman-tidy/lib/checks/beman_standard/changelog.py b/tools/beman-tidy/lib/checks/beman_standard/changelog.py index 38efa7f2..8135dd95 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/changelog.py +++ b/tools/beman-tidy/lib/checks/beman_standard/changelog.py @@ -1,10 +1,10 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.generic_file_check import BSGenericFileCheck +from ..base.file_base_check import FileBaseCheck -class BSGeneriChangelogCheck(BSGenericFileCheck): +class BSGeneriChangelogCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard, check_name): super().__init__(repo_info, beman_standard, check_name, "Changelog.md") diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index a143b1e3..6b1d72dc 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -1,12 +1,12 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.generic_file_check import BSGenericFileCheck +from ..base.file_base_check import FileBaseCheck from ...utils.string import * from ...utils.git import * -class BSGenericReadmeCheck(BSGenericFileCheck): +class BSGenericReadmeCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard, check_name): super().__init__(repo_info, beman_standard, check_name, "README.md") diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 045308b7..3e03acc1 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -1,40 +1,40 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.generic_file_check import BSGenericFileCheck +from ..base.file_base_check import FileBaseCheck from ...utils.git import * -class BSTopLevelChangelogCheck(BSGenericFileCheck): +class BSTopLevelChangelogCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.CHANGELOG", "CHANGELOG.md") def check(self): - return super().base_check() # Non-empty file check. + return super().default_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. pass -class BSTopLevelCMakeListsCheck(BSGenericFileCheck): +class BSTopLevelCMakeListsCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.CMAKE", "CMakeLists.txt") def check(self): - return super().base_check() # Non-empty file check. + return super().default_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. pass -class BSTopLevelLicenseCheck(BSGenericFileCheck): +class BSTopLevelLicenseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.LICENSE", "LICENSE") def check(self): - return super().base_check() # Non-empty file check. + return super().default_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. @@ -42,12 +42,12 @@ def fix(self): pass -class BSTopLevelREADMECheck(BSGenericFileCheck): +class BSTopLevelREADMECheck(FileBaseCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.README", "README.md") def check(self): - return super().base_check() # Non-empty file check. + return super().default_check() # Non-empty file check. def fix(self): # TODO import from beman_standard. diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index 4380f921..9d82294b 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -1,12 +1,12 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.base_check import BSCheck +from ..base.base_check import BaseCheck import sys -class BSCheckFixInplaceIncompatibleWithUnstagedChanges(BSCheck): +class BaseCheckFixInplaceIncompatibleWithUnstagedChanges(BaseCheck): """ Check if the fix can be applied inplace. """ diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index f9d552b3..d81eab4c 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -64,7 +64,7 @@ def run_check(generic_check, log_enabled=args.verbose): log( f"Running check [{bs_check.type}][{bs_check.name}] ... ") - if (bs_check.base_check() and bs_check.check()) or (not args.dry_run and bs_check.fix()): + if (bs_check.default_check() and bs_check.check()) or (not args.dry_run and bs_check.fix()): log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {green_passed}\n") return True else: @@ -78,7 +78,7 @@ def run_check(generic_check, log_enabled=args.verbose): # Internal checks if args.dry_run: - run_check(BSCheckFixInplaceIncompatibleWithUnstagedChanges, + run_check(BaseCheckFixInplaceIncompatibleWithUnstagedChanges, log_enabled=False) cnt_passed = 0 @@ -103,7 +103,7 @@ def print_coverage(repo_info, beman_standard): all_bs_implemented_checks = [check for check in all_implemented_checks if get_beman_standard_check( beman_standard, check.name) is not None] passed_bs_checks = [ - check for check in all_bs_implemented_checks if check.base_check() and check.check()] + check for check in all_bs_implemented_checks if check.default_check() and check.check()] coverage = round(len(passed_bs_checks) / len(beman_standard) * 100, 2) print( From b28eaf212bd94976bad33a9c42b2b7d64c4a6647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:41:43 +0300 Subject: [PATCH 127/371] beman-tidy: tweaks in docs --- tools/beman-tidy/lib/checks/base/base_check.py | 4 +++- tools/beman-tidy/lib/checks/base/file_base_check.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index f62e74e6..5006a2f0 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -7,7 +7,9 @@ class BaseCheck(object): """ - Base class for Beman Standard check (rule). + 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. """ def __init__(self, repo_info, beman_standard, check_name): diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index c932f1fa..6cb8ecc4 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -8,7 +8,7 @@ class FileBaseCheck(BaseCheck): """ - Base class for all Beman Standard checks that operate on a file. + Base class for checks that operate on a file. """ def __init__(self, repo_info, beman_standard, check_name, relative_path): From 2cfe1f8e9374df3e0118867a35db36f1b4d996a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:43:18 +0300 Subject: [PATCH 128/371] beman-tidy: remove TOPLEVEL.CHANGELOG --- .../lib/checks/beman_standard/toplevel.py | 13 ------------- tools/beman-tidy/lib/pipeline.py | 1 - 2 files changed, 14 deletions(-) diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 3e03acc1..13cd882d 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -4,19 +4,6 @@ from ..base.file_base_check import FileBaseCheck from ...utils.git import * - -class BSTopLevelChangelogCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "TOPLEVEL.CHANGELOG", "CHANGELOG.md") - - def check(self): - return super().default_check() # Non-empty file check. - - def fix(self): - # TODO import from beman_standard. - pass - - class BSTopLevelCMakeListsCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard): super().__init__(repo_info, beman_standard, "TOPLEVEL.CMAKE", "CMakeLists.txt") diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index d81eab4c..66d8d131 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -22,7 +22,6 @@ def get_all_implemented_checks(): """ return [ # TOPLEVEL - BSTopLevelChangelogCheck, BSTopLevelCMakeListsCheck, BSTopLevelLicenseCheck, BSTopLevelREADMECheck, From dffe5ba839aa3151158432cda7015f2d115834c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:50:57 +0300 Subject: [PATCH 129/371] beman-tidy: remove deprecated rules --- .../lib/checks/beman_standard/changelog.py | 107 ----------- .../lib/checks/beman_standard/cpp.py | 2 + .../lib/checks/beman_standard/readme.py | 177 +----------------- .../lib/checks/beman_standard/release.py | 10 + .../lib/checks/beman_standard/toplevel.py | 38 +--- tools/beman-tidy/lib/pipeline.py | 28 +-- 6 files changed, 35 insertions(+), 327 deletions(-) delete mode 100644 tools/beman-tidy/lib/checks/beman_standard/changelog.py create mode 100644 tools/beman-tidy/lib/checks/beman_standard/release.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/changelog.py b/tools/beman-tidy/lib/checks/beman_standard/changelog.py deleted file mode 100644 index 8135dd95..00000000 --- a/tools/beman-tidy/lib/checks/beman_standard/changelog.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from ..base.file_base_check import FileBaseCheck - - -class BSGeneriChangelogCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard, check_name): - super().__init__(repo_info, beman_standard, check_name, "Changelog.md") - - -# TODO CHANGELOG.TITLE -class BSChangelogTitleCheck(BSGeneriChangelogCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "CHANGELOG.TITLE") - - def check(self): - """ - The CHANGELOG.md must begin with a level 1 header with the name "Changelog". - """ - lines = self.read_lines_strip() - if len(lines) == 0: - self.log(f"CHANGELOG.md is empty.") - return False - first_line = lines[0] - - # Match the pattern - if not first_line.startswith("#") or not first_line[2:].startswith("Changelog"): - self.log( - f"CHANGELOG.md must begin with a level 1 header with the name 'Changelog'") - return False - - return True - - def fix(self): - default_line_title = "# Changelog" - - all_lines = self.read_lines_strip() - if len(all_lines) > 0 and all_lines[0].startswith("#"): - all_lines[0] = default_line_title - else: - all_lines.insert(0, default_line_title) - - all_lines.append("") # Add empty line at the end of the file. - self.write_lines(all_lines) - -# TODO CHANGELOG.FORMAT - - -class BSChangelogLibraryStatus(BSGeneriChangelogCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "CHANGELOG.LIBRARY_STATUS") - - def check(self): - """ - The CHANGELOG.md must contain a line for each previous library status with respect to the Beman library maturity model. - - The line must be in the format: - - [LIBRARY_STATUS]: Library status updated to [${LIBRARY STATUS}](${LIBRARY STATUS BADGE URL}): It was rejected from ISO standardization. - - """ - all_lines = self.read_lines_strip() - if len(all_lines) == 0: - self.log(f"CHANGELOG.md is empty.") - return False - - # Extract all beman standard library status from the full_text_body. - standard_library_status = [line for line in self.full_text_body.split( - "\n") if line.startswith("- [LIBRARY_STATUS]")] - # Extract all library status from the CHANGELOG.md - changelog_library_status = [ - line for line in all_lines if line.startswith("- [LIBRARY_STATUS]")] - - if len(changelog_library_status) == 0: - self.log(f"CHANGELOG.md must contain a line for each previous library status with respect to the Beman library maturity model. Initial library status is missing.") - return False - - for library_status in changelog_library_status: - # Check for common prefix until 3rd column. - if not any(standard_status[:standard_status.index(")") + 1] in library_status for standard_status in standard_library_status): - self.log( - f"Library status '{library_status}' is not in the correct format.") - return False - - return True - - def fix(self): - # Only if the changelog is empty, add the initial library status. - all_lines = self.read_lines_strip() - if len(all_lines) > 1: - return False - - default_change_log = [ - "# Changelog", - "", - "", - "", - "## [Unreleased]", - "", - "### Added", - "- [LIBRARY_STATUS]: Library status updated to [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): It is not yet ready for production use." - "", - "" - ] - self.write_lines(default_change_log) diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/lib/checks/beman_standard/cpp.py index cbded5c4..0300af52 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cpp.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cpp.py @@ -3,3 +3,5 @@ # TODO CPP.NAMESPACE # TODO CPP.NO_FLAG_FORKING +# TODO CPP.EXTENSION_IDENTIFIERS + diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 6b1d72dc..17c353eb 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -5,175 +5,8 @@ from ...utils.string import * from ...utils.git import * - -class BSGenericReadmeCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard, check_name): - super().__init__(repo_info, beman_standard, check_name, "README.md") - - -class BSReadmeTitleCheck(BSGenericReadmeCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "README.TITLE") - - def check(self): - """ - The README.md should begin with a level 1 header with the name of the library optionally followed - with a ":" and short description. - """ - lines = self.read_lines_strip() - if len(lines) == 0: - return False - first_line = lines[0] - - # Match the pattern "# [: ]" - if not first_line[2:].startswith(f"{self.library_name}:"): - return False - - return True - - -class BSReadmeBadgesCheck(BSGenericReadmeCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "README.BADGES") - - def check(self): - """ - Following the title, the `README.md` must have a one-line badge list: library status (`[README.LIBRARY_STATUS]`), CI status, code coverage. - - Badge format: ![Name with multiple words](url_no_spaces) - Badge line format: ![Name1](url1) ![Name2](url2) ![Name3](url3) ... - - Example: - ![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) - """ - repo_badges = self.parse_lines(self.read_lines_strip()) - if repo_badges is None: - self.log(f"First line of README.md must contain badges.") - return False - - standard_badges = match_badges(self.full_text_body) - if standard_badges is None: - self.log( - f"No badges found in Beman Standard. Please add badge examples to the Beman Standard in section README.BADGES.") - return False - - # Check if the badges in the README.md are the same as in the Beman Standard. - for badge_name, badge_url in repo_badges: - matched_badge = next( - (standard_badge for standard_badge in standard_badges if standard_badge[0] == badge_name), None) - if not matched_badge: - self.log( - f"Badge \"{badge_name}\" not found in the Beman Standard. Standard badges: {set([badge[0] for badge in standard_badges])}.") - return False - beman_standard_badge_url = matched_badge[1] - - if badge_name == "Library Status": - if not badge_url.startswith("https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_"): - self.log( - f"Badge \"{badge_name}\" URL is invalid: {badge_url}. The URL should start with \"https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_\".") - return False - - if badge_url not in [standard_badge[1] for standard_badge in standard_badges]: - self.log( - f"Badge \"{badge_name}\" URL is invalid: {badge_url}. The URL should be in the Beman Standard.") - return False - - if not validate_url(badge_url): - self.log( - f"Badge \"{badge_name}\" URL is invalid: {badge_url}.") - return False - - return True - - def parse_lines(self, lines): - if lines is None or len(lines) == 0: - return None - - lines = skip_lines(lines, 1) # Skip the title. - lines = skip_empty_lines(lines) # Skip empty lines. - # Skip 3 lines of "SPDX-License-Identifier" - lines = skip_lines(lines, 3) - lines = skip_empty_lines(lines) # Skip empty lines. - badge_line = lines[0] if len(lines) > 0 else None - lines = skip_lines(lines, 1) # Skip the badges. - if len(lines) > 0: - # No more badges on remaining lines. - if any(match_badges(line) for line in lines): - self.log(f"Only one line of badges is allowed.") - return None - - return match_badges(badge_line) - -# README.PURPOSE - - -class BSReadmeImplementsCheck(BSGenericReadmeCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "README.IMPLEMENTS") - - def check(self): - """ - Following the purpose and a newline, the README.md should indicate which papers the repository implements. - - Use the following style: - - **Implements**: [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1). - **Implements**: [`std::optional` (P2988R5)](https://wg21.link/P2988R5) and [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1). - """ - lines = self.read_lines_strip() - if len(lines) == 0: - return False - - # Find the line with "Implements", make sure is exactly one. - implements_line = next( - (line for line in lines if line.startswith("**Implements**:")), None) - if not implements_line: - self.log( - f"README.md must contain a line with \"**Implements**: ...\" after the purpose and a newline.") - return False - - # Check if the line is in the correct format. - all_paper_md_links = re.findall( - r"\[.*?\([PD][0-9]*R[0-9]*\)\]\(https://wg21.link/.*?\)", implements_line) - if len(all_paper_md_links) == 0: - self.log( - f"The \"Implements\" line must contain at least one paper link. For example:\n\"**Implements**: [Give *std::optional* Range Support (P3168R1)](https://wg21.link/P3168R1)\"") - return False - - return True - - -class BSReadmeLibraryStatusCheck(BSGenericReadmeCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "README.LIBRARY_STATUS") - - def check(self): - """ - Following the implements section and a newline, the README.md must indicate the current library status - with respect to the Beman library maturity model. - """ - lines = self.read_lines_strip() - if len(lines) == 0: - return False - - # Find the line with "Status", make sure is exactly one. - status_line = next( - (line for line in lines if line.startswith("**Status**:")), None) - if not status_line: - self.log( - f"README.md must contain a line with \"**Status**: ...\" after the implements section and a newline.") - return False - - # Check if the line is in the Beman Standard (perfect content match). - beman_standard_status_lines = [line for line in self.full_text_body.split( - "\n") if line.startswith("**Status**:")] - if len(beman_standard_status_lines) == 0: - self.log( - f"The Beman Standard must contain all possible line with format \"**Status**: ...\" in README.LIBRARY_STATUS.") - return False - if status_line not in beman_standard_status_lines: - self.log( - f"Status line \"{status_line}\" not found in the Beman Standard.") - return False - - return True +# TODO README.TITLE +# TODO README.BADGES +# TODO README.PURPOSE +# TODO README.IMPLEMENTS +# TODO README.LIBRARY_STATUS diff --git a/tools/beman-tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/lib/checks/beman_standard/release.py new file mode 100644 index 00000000..14ea5c91 --- /dev/null +++ b/tools/beman-tidy/lib/checks/beman_standard/release.py @@ -0,0 +1,10 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +from ..base.file_base_check import FileBaseCheck +from ...utils.string import * +from ...utils.git import * + +# TODO RELEASE.GITHUB +# TODO RELEASE.NOTES +# TODO RELEASE.GODBOLT_TRUNK_VERSION diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 13cd882d..6c20ecb1 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -4,38 +4,6 @@ from ..base.file_base_check import FileBaseCheck from ...utils.git import * -class BSTopLevelCMakeListsCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "TOPLEVEL.CMAKE", "CMakeLists.txt") - - def check(self): - return super().default_check() # Non-empty file check. - - def fix(self): - # TODO import from beman_standard. - pass - - -class BSTopLevelLicenseCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "TOPLEVEL.LICENSE", "LICENSE") - - def check(self): - return super().default_check() # Non-empty file check. - - def fix(self): - # TODO import from beman_standard. - self.write(download_beman_default_license()) - pass - - -class BSTopLevelREADMECheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, "TOPLEVEL.README", "README.md") - - def check(self): - return super().default_check() # Non-empty file check. - - def fix(self): - # TODO import from beman_standard. - pass +# TODO TOPLEVEL.CMAKE +# TODO TOPLEVEL.LICENSE +# TODO TOPLEVEL.README diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 66d8d131..fe090a04 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .checks.system.git import * -from .checks.beman_standard.changelog import * from .checks.beman_standard.cmake import * from .checks.beman_standard.cpp import * from .checks.beman_standard.directory import * @@ -10,6 +9,7 @@ from .checks.beman_standard.general import * from .checks.beman_standard.license import * from .checks.beman_standard.readme import * +from .checks.beman_standard.release import * from .checks.beman_standard.toplevel import * @@ -21,21 +21,23 @@ def get_all_implemented_checks(): Returns a list of checks that need to be run. """ return [ - # TOPLEVEL - BSTopLevelCMakeListsCheck, - BSTopLevelLicenseCheck, - BSTopLevelREADMECheck, + # License - # CHANGELOG - BSChangelogTitleCheck, - BSChangelogLibraryStatus, + # General + + # Release + + # Top-level # README - BSReadmeTitleCheck, - BSReadmeBadgesCheck, - # PURPOSE - BSReadmeImplementsCheck, - BSReadmeLibraryStatusCheck, + + # Cmake + + # CPP + + # Directory + + # File ] From ee6fb0d50002309c1fe0e6ab9be583837c2ffb3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 6 Jun 2025 23:55:14 +0300 Subject: [PATCH 130/371] beman-tidy: tweaks in naming --- tools/beman-tidy/lib/checks/system/git.py | 8 ++++---- tools/beman-tidy/lib/pipeline.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index 9d82294b..f0e02915 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -6,9 +6,9 @@ import sys -class BaseCheckFixInplaceIncompatibleWithUnstagedChanges(BaseCheck): +class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): """ - Check if the fix can be applied inplace. + If fix is attempted, disallow it if there are unstaged changes. """ def __init__(self, repo_info, beman_standard): @@ -17,13 +17,13 @@ def __init__(self, repo_info, beman_standard): def check(self): """ - Check already applied if no unstaged changes are present. + Should not allow fix if there are unstaged changes. """ return len(self.repo_info["unstaged_changes"]) == 0 def fix(self): """ - Fix the issue if the fix can be applied inplace, so unstaged changes are not present! + Stop the program if there are unstaged changes. """ self.log( "The fix cannot be applied inplace. Please commit or stash your changes. STOP.") diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index fe090a04..45eaf264 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -79,7 +79,7 @@ def run_check(generic_check, log_enabled=args.verbose): # Internal checks if args.dry_run: - run_check(BaseCheckFixInplaceIncompatibleWithUnstagedChanges, + run_check(DisallowFixInplaceAndUnstagedChangesCheck, log_enabled=False) cnt_passed = 0 From 95e41f484a8c465b0b731f1c16a54c57ec02e0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 01:13:57 +0300 Subject: [PATCH 131/371] beman-tidy: repo path should be positional arg --- tools/beman-tidy/.beman-standard.yml | 150 +++++++++++++++++++++++++++ tools/beman-tidy/README.md | 15 +-- tools/beman-tidy/beman-tidy | 4 +- 3 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 tools/beman-tidy/.beman-standard.yml diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/.beman-standard.yml new file mode 100644 index 00000000..fa23c3b5 --- /dev/null +++ b/tools/beman-tidy/.beman-standard.yml @@ -0,0 +1,150 @@ +beman_standard: + 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 + + LIBRARY.NAMES: + type: RECOMMENDATION + regex: + REPOSITORY.NAME: + type: RECOMMENDATION + regex: + REPOSITORY.CODEOWNERS: + type: RECOMMENDATION + default_group: "@bemanproject/core-reviewers" + REPOSITORY.DISALLOW_GIT_SUBMODULES: + type: RECOMMENDATION + + RELEASE.GITHUB: + type: REQUIREMENT + RELEASE.NOTES: + type: RECOMMENDATION + RELEASE.GODBOLT_TRUNK_VERSION: + type: RECOMMENDATION + + TOPLEVEL.CMAKE: + type: RECOMMENDATION + file_name: CMakeLists.txt + TOPLEVEL.LICENSE: + type: RECOMMENDATION + file_name: LICENSE + TOPLEVEL.README: + type: RECOMMENDATION + file_name: README.md + + README.TITLE: + type: RECOMMENDATION + README.BADGES: + type: RECOMMENDATION + badge_lines: [ + "![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: RECOMMENDATION + status_lines: [ + "**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)", + ] + + 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: RECOMMENDATION + regex: + CMAKE.TARGET_NAMES: + type: RECOMMENDATION + regex: + CMAKE.PASSIVE_TARGETS: + type: RECOMMENDATION + regex: + CMAKE.SKIP_TESTS: + type: RECOMMENDATION + regex: + CMAKE.SKIP_EXAMPLES: + type: RECOMMENDATION + regex: + CMAKE.AVOID_PASSTHROUGHS: + type: RECOMMENDATION + + DIRECTORY.INTERFACE_HEADERS: + type: RECOMMENDATION + directory_name: include + regex: + DIRECTORY.IMPLEMENTATION_HEADERS: + type: RECOMMENDATION + regex: + DIRECTORY.SOURCES: + type: RECOMMENDATION + directory_name: src + regex: + DIRECTORY.TESTS: + type: RECOMMENDATION + directory_name: tests + regex: + DIRECTORY.EXAMPLES: + type: RECOMMENDATION + directory_name: examples + regex: + DIRECTORY.DOCS: + type: RECOMMENDATION + directory_name: docs + regex: + DIRECTORY.PAPERS: + type: RECOMMENDATION + directory_name: papers + + + FILE.CPP_NAMES: + type: RECOMMENDATION + regex: + FILE.TEST_NAMES: + type: RECOMMENDATION + regex: + FILE.LICENSE_ID: + type: RECOMMENDATION + regex: [ + "// SPDX-License-Identifier: ", + "# SPDX-License-Identifier: ", + "" + ] + FILE.COPYRIGHT: + type: RECOMMENDATION + regex: + + CPP.NAMESPACE: + type: RECOMMENDATION + CPP.NO_FLAG_FORKING: + type: RECOMMENDATION + CPP.EXTENSION_IDENTIFIERS: + type: RECOMMENDATION diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index e71aa5c1..91704f8c 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -19,25 +19,20 @@ $ pip3 install -r requirements.txt ```shell # Display help. $ ./tools/beman-tidy/beman-tidy --help -usage: beman-tidy [-h] --repo-path REPO_PATH [--dry-run | --no-dry-run] [--verbose | --no-verbose] +usage: beman-tidy repo_path [-h] [--dry-run | --no-dry-run] [--verbose | --no-verbose] + +positional arguments: + repo_path path to the repository to check optional arguments: -h, --help show this help message and exit - --repo-path REPO_PATH - path to the repository to check --dry-run, --no-dry-run DO NOT try to automatically fix found issues (default: False) --verbose, --no-verbose print verbose output for each check (default: False) -# Run beman-tidy on the exemplar repository (automatically fix issues). -$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar -Summary: 8 checks PASSED, 2 checks FAILED, 35 skipped (not implemented). - -Coverage: 17.78% (8/45 checks passed). - # Run beman-tidy on the exemplar repository (automatically fix issues, verbose output). -$ ./tools/beman-tidy/beman-tidy --repo-path ../exemplar --verbose +$ ./tools/beman-tidy/beman-tidy ../exemplar --verbose beman-tidy started ... Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 01248bd3..849b1675 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -11,8 +11,8 @@ def parse_args(): """ parser = argparse.ArgumentParser() - parser.add_argument("--repo-path", help="path to the repository to check", - required=True, type=str) + parser.add_argument("repo_path", help="path to the repository to check", + type=str) parser.add_argument("--dry-run", help="DO NOT try to automatically fix found issues", action=argparse.BooleanOptionalAction, type=bool, default=False) parser.add_argument("--verbose", help="print verbose output for each check", From c45e5a6cd1cba98370382b8b46ceeb2d2aef7c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 02:47:14 +0300 Subject: [PATCH 132/371] beman-tidy: add .beman-standard.yml and checks registry --- tools/beman-tidy/.beman-standard.yml | 257 +++++++++--------- tools/beman-tidy/beman-tidy | 18 +- .../beman-tidy/lib/checks/base/base_check.py | 36 +-- .../lib/checks/base/file_base_check.py | 5 +- .../lib/checks/beman_standard/readme.py | 107 ++++++++ tools/beman-tidy/lib/checks/system/git.py | 4 +- .../beman-tidy/lib/checks/system/registry.py | 40 +++ tools/beman-tidy/lib/pipeline.py | 136 +++++---- tools/beman-tidy/lib/utils/git.py | 118 ++++---- tools/beman-tidy/lib/utils/string.py | 4 +- tools/beman-tidy/requirements.txt | 1 + 11 files changed, 417 insertions(+), 309 deletions(-) create mode 100644 tools/beman-tidy/lib/checks/system/registry.py diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/.beman-standard.yml index fa23c3b5..3d9ae6d3 100644 --- a/tools/beman-tidy/.beman-standard.yml +++ b/tools/beman-tidy/.beman-standard.yml @@ -1,150 +1,149 @@ -beman_standard: - 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 + - 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 - LIBRARY.NAMES: - type: RECOMMENDATION - regex: - REPOSITORY.NAME: - type: RECOMMENDATION - regex: - REPOSITORY.CODEOWNERS: - type: RECOMMENDATION - default_group: "@bemanproject/core-reviewers" - REPOSITORY.DISALLOW_GIT_SUBMODULES: - type: RECOMMENDATION +LIBRARY.NAMES: + - type: RECOMMENDATION + - regex: +REPOSITORY.NAME: + - type: RECOMMENDATION + - regex: +REPOSITORY.CODEOWNERS: + - type: RECOMMENDATION + - default_group: "@bemanproject/core-reviewers" +REPOSITORY.DISALLOW_GIT_SUBMODULES: + - type: RECOMMENDATION - 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 - TOPLEVEL.CMAKE: - type: RECOMMENDATION - file_name: CMakeLists.txt - TOPLEVEL.LICENSE: - type: RECOMMENDATION - file_name: LICENSE - TOPLEVEL.README: - type: RECOMMENDATION - file_name: README.md +TOPLEVEL.CMAKE: + - type: RECOMMENDATION + - file_name: CMakeLists.txt +TOPLEVEL.LICENSE: + - type: RECOMMENDATION + - file_name: LICENSE +TOPLEVEL.README: + - type: RECOMMENDATION + - file_name: README.md - README.TITLE: - type: RECOMMENDATION - README.BADGES: - type: RECOMMENDATION - badge_lines: [ +README.TITLE: + - type: RECOMMENDATION +README.BADGES: + - type: RECOMMENDATION + - badge_lines: [ "![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: RECOMMENDATION - status_lines: [ +README.PURPOSE: + - type: RECOMMENDATION +README.IMPLEMENTS: + - type: RECOMMENDATION +README.LIBRARY_STATUS: + - type: RECOMMENDATION + - status_lines: [ "**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)", ] - - 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: RECOMMENDATION - regex: - CMAKE.TARGET_NAMES: - type: RECOMMENDATION - regex: - CMAKE.PASSIVE_TARGETS: - type: RECOMMENDATION - regex: - CMAKE.SKIP_TESTS: - type: RECOMMENDATION - regex: - CMAKE.SKIP_EXAMPLES: - type: RECOMMENDATION - regex: - CMAKE.AVOID_PASSTHROUGHS: - type: RECOMMENDATION - DIRECTORY.INTERFACE_HEADERS: - type: RECOMMENDATION - directory_name: include - regex: - DIRECTORY.IMPLEMENTATION_HEADERS: - type: RECOMMENDATION - regex: - DIRECTORY.SOURCES: - type: RECOMMENDATION - directory_name: src - regex: - DIRECTORY.TESTS: - type: RECOMMENDATION - directory_name: tests - regex: - DIRECTORY.EXAMPLES: - type: RECOMMENDATION - directory_name: examples - regex: - DIRECTORY.DOCS: - type: RECOMMENDATION - directory_name: docs - regex: - DIRECTORY.PAPERS: - type: RECOMMENDATION - directory_name: papers +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: RECOMMENDATION + - regex: +CMAKE.TARGET_NAMES: + - type: RECOMMENDATION + - regex: +CMAKE.PASSIVE_TARGETS: + - type: RECOMMENDATION + - regex: +CMAKE.SKIP_TESTS: + - type: RECOMMENDATION + - regex: +CMAKE.SKIP_EXAMPLES: + - type: RECOMMENDATION + - regex: +CMAKE.AVOID_PASSTHROUGHS: + - type: RECOMMENDATION - - FILE.CPP_NAMES: - type: RECOMMENDATION - regex: - FILE.TEST_NAMES: - type: RECOMMENDATION - regex: - FILE.LICENSE_ID: - type: RECOMMENDATION - regex: [ +DIRECTORY.INTERFACE_HEADERS: + - type: RECOMMENDATION + - directory_name: include + - regex: +DIRECTORY.IMPLEMENTATION_HEADERS: + - type: RECOMMENDATION + - regex: +DIRECTORY.SOURCES: + - type: RECOMMENDATION + - directory_name: src + - regex: +DIRECTORY.TESTS: + - type: RECOMMENDATION + - directory_name: tests + - regex: +DIRECTORY.EXAMPLES: + - type: RECOMMENDATION + - directory_name: examples + - regex: +DIRECTORY.DOCS: + - type: RECOMMENDATION + - directory_name: docs + - regex: +DIRECTORY.PAPERS: + - type: RECOMMENDATION + - directory_name: papers + + +FILE.CPP_NAMES: + - type: RECOMMENDATION + - regex: +FILE.TEST_NAMES: + - type: RECOMMENDATION + - regex: +FILE.LICENSE_ID: + - type: RECOMMENDATION + - regex: [ "// SPDX-License-Identifier: ", "# SPDX-License-Identifier: ", "" ] - FILE.COPYRIGHT: - type: RECOMMENDATION - regex: +FILE.COPYRIGHT: + - type: RECOMMENDATION + - regex: - CPP.NAMESPACE: - type: RECOMMENDATION - CPP.NO_FLAG_FORKING: - type: RECOMMENDATION - CPP.EXTENSION_IDENTIFIERS: - type: RECOMMENDATION +CPP.NAMESPACE: + - type: RECOMMENDATION +CPP.NO_FLAG_FORKING: + - type: RECOMMENDATION +CPP.EXTENSION_IDENTIFIERS: + - type: RECOMMENDATION diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 849b1675..070fa6cd 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -17,11 +17,12 @@ def parse_args(): action=argparse.BooleanOptionalAction, type=bool, default=False) parser.add_argument("--verbose", help="print verbose output for each check", action=argparse.BooleanOptionalAction, type=bool, default=False) + parser.add_argument("--checks", help="array of checks to run", + type=str, default=None) args = parser.parse_args() - # Get repository information - repo_info = get_repo_info(args.repo_path) - args.repo_info = repo_info + args.repo_info = get_repo_info(args.repo_path) + args.checks = args.checks.split(",") if args.checks else None return args @@ -32,17 +33,14 @@ def main(): """ args = parse_args() - # No action can be performed without the Beman Standard downloaded. - beman_standard = download_beman_standard() - if not beman_standard or len(beman_standard) == 0: + beman_standard_check_config = load_beman_standard_config(".beman-standard.yml") + if not beman_standard_check_config or len(beman_standard_check_config) == 0: print("Failed to download the beman standard. STOP.") return - # Actually run the checks. - run_checks_pipeline(args, beman_standard) + checks_to_run = [check for check in beman_standard_check_config] if args.checks is None else args.checks - # Show coverage. - print_coverage(args.repo_info, beman_standard) + run_checks_pipeline(checks_to_run, args, beman_standard_check_config) if __name__ == "__main__": main() diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 5006a2f0..cee304b2 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -3,7 +3,7 @@ import os import sys - +from ..system.registry import * class BaseCheck(object): """ @@ -12,41 +12,35 @@ class BaseCheck(object): e.g., check for repository name, check for changelog, check for license, etc. """ - def __init__(self, repo_info, beman_standard, check_name): + def __init__(self, repo_info, beman_standard_check_config, name=None): """ Create a new check instance. """ - # check name e.g. "LIBRARY.NAMES" - self.name = check_name - - # unique entry in the list - [(check_name, check_type, check_full_text_body)] - beman_standard_check = [ - entry for entry in beman_standard if entry[0] == check_name] - assert len(beman_standard_check) <= 1 - - # set type and full_text_body - if len(beman_standard_check) == 1: - (check_name, check_type, check_body) = beman_standard_check[0] - - self.type = check_type - self.full_text_body = check_body - else: - self.type = "REQUIREMENT" - self.full_text_body = "beman-tidy internal check." + + # check name - e.g. "README.TITLE" + self.name = name if name is not None else get_beman_standard_check_name_by_class(self.__class__) + assert self.name is not None, f"Check name not found for class: {self.__class__.__name__}" + + # set type - e.g. "REQUIREMENT" or "RECOMMENDATION" + self.type = beman_standard_check_config[self.name]["type"] 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"] 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' self.log_enabled = False + # set repo info self.repo_info = repo_info - assert "name" in repo_info self.repo_name = repo_info["name"] assert "top_level" in repo_info self.repo_path = repo_info["top_level"] - + assert self.repo_path is not None self.library_name = f"beman.{self.repo_name}" assert self.library_name is not None diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index 6cb8ecc4..7ae89200 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -11,9 +11,10 @@ class FileBaseCheck(BaseCheck): Base class for checks that operate on a file. """ - def __init__(self, repo_info, beman_standard, check_name, relative_path): - super().__init__(repo_info, beman_standard, check_name) + def __init__(self, repo_info, beman_standard_check_config, relative_path): + super().__init__(repo_info, beman_standard_check_config) + # set path - e.g. "README.md" self.path = os.path.join(repo_info["top_level"], relative_path) def default_check(self): diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 17c353eb..5f11c28c 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -4,9 +4,116 @@ from ..base.file_base_check import FileBaseCheck from ...utils.string import * from ...utils.git import * +from ..system.registry import register_beman_standard_check # TODO README.TITLE # TODO README.BADGES # TODO README.PURPOSE # TODO README.IMPLEMENTS # TODO README.LIBRARY_STATUS + + +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") +class ReadmeTitleCheck(ReadmeBaseCheck): + """ + Check https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmetitle + """ + 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() + if len(lines) == 0: + return False + first_line = lines[0] + + # Match the pattern "# [: ]" + if not first_line[2:].startswith(f"{self.library_name}:"): + return False + + return True + + def fix(self): + """ + Fix the issue if the Beman Standard is not applied. + """ + # TODO: Implement the fix. + return False + + +@register_beman_standard_check("README.BADGES") +class ReadmeBadgesCheck(ReadmeBaseCheck): + """ + Check https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmebadges + """ + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + """ + Badge format: ![Name with multiple words](url_no_spaces) + Badge line format: ![Name1](url1) ![Name2](url2) ![Name3](url3) ... + """ + repo_badges = self.parse_lines(self.read_lines_strip()) + if repo_badges is None: + self.log(f"First line of README.md must contain badges.") + return False + + standard_badges = match_badges(self.full_text_body) + if standard_badges is None: + self.log( + f"No badges found in Beman Standard. Please add badge examples to the Beman Standard in section README.BADGES.") + return False + + # Check if the badges in the README.md are the same as in the Beman Standard. + for badge_name, badge_url in repo_badges: + matched_badge = next( + (standard_badge for standard_badge in standard_badges if standard_badge[0] == badge_name), None) + if not matched_badge: + self.log( + f"Badge \"{badge_name}\" not found in the Beman Standard. Standard badges: {set([badge[0] for badge in standard_badges])}.") + return False + beman_standard_badge_url = matched_badge[1] + + if badge_name == "Library Status": + if not badge_url.startswith("https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_"): + self.log( + f"Badge \"{badge_name}\" URL is invalid: {badge_url}. The URL should start with \"https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_\".") + return False + + if badge_url not in [standard_badge[1] for standard_badge in standard_badges]: + self.log( + f"Badge \"{badge_name}\" URL is invalid: {badge_url}. The URL should be in the Beman Standard.") + return False + + if not validate_url(badge_url): + self.log( + f"Badge \"{badge_name}\" URL is invalid: {badge_url}.") + return False + + return True + + def parse_lines(self, lines): + if lines is None or len(lines) == 0: + return None + + lines = skip_lines(lines, 1) # Skip the title. + lines = skip_empty_lines(lines) # Skip empty lines. + # Skip 3 lines of "SPDX-License-Identifier" + lines = skip_lines(lines, 3) + lines = skip_empty_lines(lines) # Skip empty lines. + badge_line = lines[0] if len(lines) > 0 else None + lines = skip_lines(lines, 1) # Skip the badges. + if len(lines) > 0: + # No more badges on remaining lines. + if any(match_badges(line) for line in lines): + self.log(f"Only one line of badges is allowed.") + return None + + return match_badges(badge_line) diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index f0e02915..9aadcd3c 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -11,8 +11,8 @@ class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): If fix is attempted, disallow it if there are unstaged changes. """ - def __init__(self, repo_info, beman_standard): - super().__init__(repo_info, beman_standard, + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, 'NO_UNSTAGED_CHANGES') def check(self): diff --git a/tools/beman-tidy/lib/checks/system/registry.py b/tools/beman-tidy/lib/checks/system/registry.py new file mode 100644 index 00000000..081c7ddd --- /dev/null +++ b/tools/beman-tidy/lib/checks/system/registry.py @@ -0,0 +1,40 @@ +from typing import Dict, Type, List + +# Registry to store all The Beman Standard check classes. +_beman_standard_check_registry: Dict[str, Type] = {} + +def register_beman_standard_check(check: str): + """ + Decorator to register a check class with a specific ID. + + Usage: + @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. + """ + def decorator(check_class: Type) -> Type: + _beman_standard_check_registry[check] = check_class + return check_class + return decorator + +def get_registered_beman_standard_checks() -> Dict[str, Type]: + """Get all registered check classes""" + return _beman_standard_check_registry.copy() + +def get_beman_standard_check_by_name(check_name: str) -> Type: + """Get a specific check class by its name""" + return _beman_standard_check_registry.get(check_name) + +def get_all_beman_standard_check_names() -> List[str]: + """Get all registered check names""" + return list(_beman_standard_check_registry.keys()) + +def get_beman_standard_check_name_by_class(target_check_class: Type) -> str: + """Get the name of a check class""" + for check_name, check_class in _beman_standard_check_registry.items(): + if check_class == target_check_class: + return check_name + return None diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 45eaf264..2467d163 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -1,6 +1,8 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from .checks.system.registry import * + from .checks.system.git import * from .checks.beman_standard.cmake import * from .checks.beman_standard.cpp import * @@ -12,100 +14,90 @@ from .checks.beman_standard.release import * from .checks.beman_standard.toplevel import * +red_color = "\033[91m" +green_color = "\033[92m" +yellow_color = "\033[93m" +gray_color = "\033[90m" +no_color = "\033[0m" -def get_all_implemented_checks(): - """ - Get the checks pipeline - it is a list of checks, that need to be run. - The list may contain checks that are not from The Beman Standard. - - Returns a list of checks that need to be run. - """ - return [ - # License - - # General - - # Release - - # Top-level - - # README - - # Cmake - - # CPP - - # Directory - - # File - ] - - -def get_beman_standard_check(beman_standard, check_name): - """ - Get The Beman Standard check object from the Beman Standard that matches the check_name. - """ - return next(filter(lambda bs_check: bs_check[0] == check_name, beman_standard), None) - - -def run_checks_pipeline(args, beman_standard): +def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): """ Run the checks pipeline for The Beman Standard. Read-only checks if args.dry_run is True, otherwise try to fix the issues in-place. Verbosity is controlled by args.verbose. """ + + """ + Helper function to log messages. + """ def log(msg): if args.verbose: print(msg) - def run_check(generic_check, log_enabled=args.verbose): - bs_check = generic_check(args.repo_info, beman_standard) - bs_check.log_enabled = log_enabled + """ + 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): + check_instance = check_class(args.repo_info, beman_standard_check_config) + check_instance.log_enabled = log_enabled log( - f"Running check [{bs_check.type}][{bs_check.name}] ... ") + f"Running check [{check_instance.type}][{check_instance.name}] ... ") - if (bs_check.default_check() and bs_check.check()) or (not args.dry_run and bs_check.fix()): - log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {green_passed}\n") + if (check_instance.default_check() and check_instance.check()) or (not args.dry_run and check_instance.fix()): + log(f"\tcheck [{check_instance.type}][{check_instance.name}] ... {green_color}PASSED{no_color}\n") return True else: - log(f"\tcheck [{bs_check.type}][{bs_check.name}] ... {red_failed}\n") + log(f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}FAILED{no_color}\n") return False - red_failed = "\033[91mFAILED\033[0m" - green_passed = "\033[92mPASSED\033[0m" - - log("beman-tidy started ...\n") - - # Internal checks - if args.dry_run: - run_check(DisallowFixInplaceAndUnstagedChangesCheck, - log_enabled=False) - - cnt_passed = 0 - cnt_failed = 0 - for generic_check in get_all_implemented_checks(): - if run_check(generic_check): - cnt_passed += 1 - else: - cnt_failed += 1 - - log("\nbeman-tidy finished.\n") - print(f"Summary: {cnt_passed} checks {green_passed}, {cnt_failed} checks {red_failed}, {len(beman_standard) - len(get_all_implemented_checks())} skipped (not implemented).") + """ + Main pipeline. + """ + def run_pipeline_helper(): + # Internal checks + if args.dry_run: + run_check(DisallowFixInplaceAndUnstagedChangesCheck, + log_enabled=False) + + implemented_checks = get_registered_beman_standard_checks() + cnt_passed = 0 + cnt_failed = 0 + cnt_skipped = len(beman_standard_check_config) - len(implemented_checks) + cnt_all_beman_standard_checks = len(beman_standard_check_config) + for check_name in checks_to_run: + if not check_name in implemented_checks: + continue + + if run_check(implemented_checks[check_name]): + cnt_passed += 1 + else: + cnt_failed += 1 + + return cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks + + + log("beman-tidy pipeline started ...\n") + cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks = run_pipeline_helper() + log("\nbeman-tidy pipeline finished.\n") + + # Always print the summary. + print(f"Summary: {green_color} {cnt_passed} checks PASSED{no_color}, {red_color}{cnt_failed} checks FAILED{no_color}, {gray_color}{cnt_skipped} skipped (NOT implemented).{no_color}") + sys.stdout.flush() + # Show coverage. + print_coverage(cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks) + -def print_coverage(repo_info, beman_standard): +def print_coverage(cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks): """ Print The Beman Standard coverage. """ - all_implemented_checks = [generic_check( - repo_info, beman_standard) for generic_check in get_all_implemented_checks()] - all_bs_implemented_checks = [check for check in all_implemented_checks if get_beman_standard_check( - beman_standard, check.name) is not None] - passed_bs_checks = [ - check for check in all_bs_implemented_checks if check.default_check() and check.check()] - coverage = round(len(passed_bs_checks) / len(beman_standard) * 100, 2) + coverage = round(cnt_passed / cnt_all_beman_standard_checks * 100, 2) print( - f"\n\033[93mCoverage: {coverage}% ({len(passed_bs_checks)}/{len(beman_standard)} checks passed).\033[0m") + f"\n{yellow_color}Coverage: {coverage}% ({cnt_passed}/{cnt_all_beman_standard_checks} checks passed).{no_color}") diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 67cb916d..cba39d9a 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -7,6 +7,7 @@ import re import requests import sys +import yaml from git import Repo, InvalidGitRepositoryError @@ -61,76 +62,51 @@ def get_repo_info(path): f"An error occurred while getting repository information. Check {path}.") sys.exit(1) - -def parse_beman_standard(beman_standard_md_content): - """ - Parse the Markdown content to extract checks from The Beman Standard - - Args: - markdown_content (str): The raw Markdown content. - - Returns: - [(check_name, check_type, check_body)]: A list of check tuples. - """ - # Regex pattern to match checks - pattern = r"\*\*\[([A-Z._]+)\]\*\* (REQUIREMENT|RECOMMENDATION):\s*(.*?)(?=\*\*\[|$)" - matches = re.finditer(pattern, beman_standard_md_content, re.DOTALL) - - bs_checks = [] - for match in matches: - check_name = match.group(1) - check_type = match.group(2) - check_body = match.group(3).strip() - - bs_checks.append((check_name, check_type, check_body)) - - return bs_checks - - -def download_file(url): +def load_beman_standard_config(path): """ - Download a file from the given URL. + Load the Beman Standard YAML configuration file from the given path. """ - try: - # Fetch the content - response = requests.get(url) - response.raise_for_status() # Raise an exception for HTTP errors - return response.text - except requests.RequestException as e: - print( - f"An error occurred while downloading from ${raw_url}: {e}.\nSTOP.") - sys.exit(1) - - -def download_beman_standard(): - """ - Download and parse The Beman Standard content from the GitHub repository. - """ - # Raw GitHub URL for the Markdown file - # raw_url = "https://raw.githubusercontent.com/bemanproject/beman/main/docs/BEMAN_STANDARD.md" - raw_url = "https://raw.githubusercontent.com/bemanproject/beman/neatudarius-patch-9/docs/BEMAN_STANDARD.md" - beman_standard_md_content = download_file(raw_url) - bs_checks = parse_beman_standard(beman_standard_md_content) - return bs_checks - - -def download_beman_default_license(): - """ - Download and parse the default Beman LICENSE content from the GitHub repository. - """ - raw_url = "https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/LICENSE" - licent_content = download_file(raw_url) - return licent_content - - -def validate_url(url): - """ - Validate the URL. - """ - import requests - try: - response = requests.get(url) - response.raise_for_status() - return True - except requests.RequestException as e: - return False + with open(path, "r") as file: + beman_standard_yml = yaml.safe_load(file) + + beman_standard_check_config = {} + for check_name in beman_standard_yml: + check_config = { + "name": check_name, + "full_text_body": "", + "type": "", + "regex": "", + "file_name": "", + "directory_name": "", + "badge_lines": "", + "status_lines": "", + "licenses": "", + "default_group": "", + } + for entry in beman_standard_yml[check_name]: + if "type" in entry: + check_config["type"] = entry["type"] + elif "regex" in entry: + # TODO: Implement the regex check. + pass + elif "file_name" in entry: + check_config["file_name"] = entry["file_name"] + elif "directory_name" in entry: + check_config["directory_name"] = entry["directory_name"] + elif "badge_lines" in entry: + # TODO: Implement the badge check. + pass + elif "status_lines" in entry: + # TODO: Implement the status check. + pass + elif "licenses" in entry: + # TODO: Implement the license check. + pass + elif "default_group" in entry: + check_config["default_group"] = entry["default_group"] + else: + raise ValueError(f"Invalid entry in Beman Standard YAML: {entry}") + + beman_standard_check_config[check_name] = check_config + + return beman_standard_check_config diff --git a/tools/beman-tidy/lib/utils/string.py b/tools/beman-tidy/lib/utils/string.py index 770aa493..a0082471 100644 --- a/tools/beman-tidy/lib/utils/string.py +++ b/tools/beman-tidy/lib/utils/string.py @@ -1,7 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from .git import download_beman_default_license import re @@ -20,7 +19,7 @@ def is_beman_snake_case(name): def match_badges(string): """ - ![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) + e.g., ![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) """ if string is None: return None @@ -40,3 +39,4 @@ def skip_empty_lines(lines): while len(lines) > 0 and len(lines[0].strip()) == 0: lines = lines[1:] return lines + diff --git a/tools/beman-tidy/requirements.txt b/tools/beman-tidy/requirements.txt index b7e2f16e..65b6c5cd 100644 --- a/tools/beman-tidy/requirements.txt +++ b/tools/beman-tidy/requirements.txt @@ -1,3 +1,4 @@ GitPython==3.1.44 Markdown==3.4.4 Requests==2.32.3 +pyyaml==6.0.2 From 88c98c925a49a0768bf9450c7438ffafb63335ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 04:03:11 +0300 Subject: [PATCH 133/371] beman-tidy: write tests for README.TITLE --- .gitignore | 13 ++++++++ tools/beman-tidy/README.md | 20 +++++++++++ .../lib/checks/base/file_base_check.py | 8 +++++ .../lib/checks/beman_standard/readme.py | 15 ++++++--- tools/beman-tidy/lib/utils/git.py | 4 --- tools/beman-tidy/requirements.txt | 1 + tools/beman-tidy/tests/__init__.py | 3 ++ .../tests/beman_standard/__init__.py | 3 ++ .../tests/beman_standard/readme/__init__.py | 3 ++ .../tests/beman_standard/readme/conftest.py | 27 +++++++++++++++ .../readme/data/invalid/README.md | 5 +++ .../readme/data/valid/README.md | 5 +++ .../beman_standard/readme/test_readme.py | 33 +++++++++++++++++++ tools/beman-tidy/tests/conftest.py | 26 +++++++++++++++ tools/beman-tidy/tests/utils/__init__.py | 0 tools/beman-tidy/tests/utils/conftest.py | 21 ++++++++++++ 16 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 tools/beman-tidy/tests/__init__.py create mode 100644 tools/beman-tidy/tests/beman_standard/__init__.py create mode 100644 tools/beman-tidy/tests/beman_standard/readme/__init__.py create mode 100644 tools/beman-tidy/tests/beman_standard/readme/conftest.py create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/test_readme.py create mode 100644 tools/beman-tidy/tests/conftest.py create mode 100644 tools/beman-tidy/tests/utils/__init__.py create mode 100644 tools/beman-tidy/tests/utils/conftest.py diff --git a/.gitignore b/.gitignore index 259148fa..e97d5978 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,16 @@ *.exe *.out *.app + +# Python +__pycache__/ +.pytest_cache/ +*.pyc +*.pyo +*.pyd +*.pyw +*.pyz +*.pywz +*.pyzw +*.pyzwz +*.delete_me diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 91704f8c..8d3b0db7 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -74,3 +74,23 @@ Summary: 8 checks PASSED, 2 checks FAILED, 35 skipped (not implemented). Coverage: 17.78% (8/45 checks passed). ``` + +## Tests + +Run the tests: + +```shell +$ python3.9 -m pytest tests/ -v +========================================================================================================= test session starts ========================================================================================================= +platform darwin -- Python 3.9.6, pytest-8.4.0, pluggy-1.6.0 -- /Library/Developer/CommandLineTools/usr/bin/python3.9 +cachedir: .pytest_cache +rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy +collected 3 items + +tests/beman_standard/readme/test_readme.py::test_valid_readme_title PASSED [ 33%] +tests/beman_standard/readme/test_readme.py::test_invalid_readme_title PASSED [ 66%] +tests/beman_standard/readme/test_readme.py::test_fix_invalid_readme_title PASSED [100%] + +========================================================================================================== 3 passed in 0.08s ========================================================================================================== + +``` diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index 7ae89200..c8a88f7c 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -79,3 +79,11 @@ def write_lines(self, lines): Write the lines to the file. """ self.write("\n".join(lines)) + + def replace_line(self, line_number, new_line): + """ + Replace the line at the given line number with the new line. + """ + lines = self.read_lines() + lines[line_number] = new_line + self.write_lines(lines) diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 5f11c28c..1c0c903c 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -27,14 +27,20 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - + print(f"self.path: {self.path}") + print(f"self.library_name: {self.library_name}") + lines = self.read_lines_strip() if len(lines) == 0: + self.log(f"The file '{self.path}' is empty.") return False first_line = lines[0] # Match the pattern "# [: ]" - if not first_line[2:].startswith(f"{self.library_name}:"): + regex = r"^# (beman\.[a-zA-Z0-9_]+)(: (.*))?$" + match = re.match(regex, first_line) + if not match: + self.log(f"The first line of the file '{self.path}' is invalid. It should start with '# [: ]'.") return False return True @@ -43,8 +49,9 @@ def fix(self): """ Fix the issue if the Beman Standard is not applied. """ - # TODO: Implement the fix. - return False + new_title_line = f"# {self.library_name}: TODO Short Description" + self.replace_line(0, new_title_line) + return True @register_beman_standard_check("README.BADGES") diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index cba39d9a..89d43d39 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -1,11 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from .terminal import run_command -import markdown import os -import re -import requests import sys import yaml diff --git a/tools/beman-tidy/requirements.txt b/tools/beman-tidy/requirements.txt index 65b6c5cd..cbf5dcac 100644 --- a/tools/beman-tidy/requirements.txt +++ b/tools/beman-tidy/requirements.txt @@ -2,3 +2,4 @@ GitPython==3.1.44 Markdown==3.4.4 Requests==2.32.3 pyyaml==6.0.2 +pytest==8.4.0 diff --git a/tools/beman-tidy/tests/__init__.py b/tools/beman-tidy/tests/__init__.py new file mode 100644 index 00000000..b8a67863 --- /dev/null +++ b/tools/beman-tidy/tests/__init__.py @@ -0,0 +1,3 @@ +""" +Test package for beman-tidy. +""" \ No newline at end of file diff --git a/tools/beman-tidy/tests/beman_standard/__init__.py b/tools/beman-tidy/tests/beman_standard/__init__.py new file mode 100644 index 00000000..e05ac54f --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/__init__.py @@ -0,0 +1,3 @@ +""" +Tests for Beman Standard checks. +""" diff --git a/tools/beman-tidy/tests/beman_standard/readme/__init__.py b/tools/beman-tidy/tests/beman_standard/readme/__init__.py new file mode 100644 index 00000000..1cc026ee --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/__init__.py @@ -0,0 +1,3 @@ +""" +Tests for README checks. +""" diff --git a/tools/beman-tidy/tests/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/beman_standard/readme/conftest.py new file mode 100644 index 00000000..43f34a50 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/conftest.py @@ -0,0 +1,27 @@ +import os +import pytest +from pathlib import Path +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config + +@pytest.fixture +def test_data_dir(): + """Return the path to the test data directory""" + return Path(__file__).parent / "data" + +@pytest.fixture +def valid_readme_path(test_data_dir): + """Return the path to a valid README.md file""" + return test_data_dir / "valid" / "README.md" + +@pytest.fixture +def invalid_readme_path(test_data_dir): + """Return the path to an invalid README.md file""" + return test_data_dir / "invalid" / "README.md" + +@pytest.fixture(autouse=True) +def repo_info(mock_repo_info): + return mock_repo_info + +@pytest.fixture +def beman_standard_check_config(mock_beman_standard_check_config): + return mock_beman_standard_check_config diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md new file mode 100644 index 00000000..ff799387 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md @@ -0,0 +1,5 @@ +# Wrong Title Format + +This is an invalid README.md file that doesn't follow the Beman Standard: the title doesn't include the library name in the correct format. + +Note: Other checks are not run for this test!!! diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md new file mode 100644 index 00000000..07725718 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md @@ -0,0 +1,5 @@ +# beman.examplar: A Beman Library Exemplar + +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. + +Note: Other checks are not run for this test!!! diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py new file mode 100644 index 00000000..2e7c6ac5 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -0,0 +1,33 @@ +import pytest +from pathlib import Path +from lib.checks.beman_standard.readme import ReadmeTitleCheck + +def test_valid_readme_title(repo_info, beman_standard_check_config, valid_readme_path): + """Test that a valid README.md title passes the check""" + check_instance = ReadmeTitleCheck(repo_info, beman_standard_check_config) + check_instance.path = valid_readme_path + + assert check_instance.default_check() is True + assert check_instance.check() is True + +def test_invalid_readme_title(repo_info, beman_standard_check_config, invalid_readme_path): + """Test that an invalid README.md title fails the check""" + check_instance = ReadmeTitleCheck(repo_info, beman_standard_check_config) + check_instance.path = invalid_readme_path + + assert check_instance.default_check() is True + assert check_instance.check() is False + +def test_fix_invalid_readme_title(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): + """Test that the fix method corrects an invalid README.md title""" + check_instance = ReadmeTitleCheck(repo_info, beman_standard_check_config) + check_instance.path = f"{invalid_readme_path}.delete_me" + check_instance.write(invalid_readme_path.read_text()) + + assert check_instance.default_check() is True + assert check_instance.check() is False + + assert check_instance.fix() is True + + assert check_instance.default_check() is True + assert check_instance.check() is True diff --git a/tools/beman-tidy/tests/conftest.py b/tools/beman-tidy/tests/conftest.py new file mode 100644 index 00000000..9d9912a4 --- /dev/null +++ b/tools/beman-tidy/tests/conftest.py @@ -0,0 +1,26 @@ +import pytest +import os +from pathlib import Path + +def pytest_configure(config): + """ + Add custom markers to pytest. + """ + config.addinivalue_line( + "markers", "use_test_repo: mark test to use test repository instead of exemplar" + ) + +@pytest.fixture(autouse=True) +def _setup_test_environment(): + """ + Setup test environment variables and paths. + This runs automatically for all tests. + """ + # Get the root directory of the project + root_dir = Path(__file__).parent.parent + + # Add the project root to PYTHONPATH if not already there + if str(root_dir) not in os.environ.get('PYTHONPATH', ''): + os.environ['PYTHONPATH'] = f"{root_dir}:{os.environ.get('PYTHONPATH', '')}" + + yield diff --git a/tools/beman-tidy/tests/utils/__init__.py b/tools/beman-tidy/tests/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/utils/conftest.py b/tools/beman-tidy/tests/utils/conftest.py new file mode 100644 index 00000000..a1adbcbb --- /dev/null +++ b/tools/beman-tidy/tests/utils/conftest.py @@ -0,0 +1,21 @@ +import pytest +from lib.utils.git import load_beman_standard_config + +@pytest.fixture +def mock_repo_info(): + """Return repository information for beman.exemplar library""" + return { + "top_level": ".", + "name": "exemplar", + "remote_url": "https://github.com/bemanproject/exemplar", + "current_branch": "main", + "commit_hash": 0, + "status": "", + "unstaged_changes": "", + } + +@pytest.fixture +def mock_beman_standard_check_config(): + """Parse the Beman Standard YAML file and return a dictionary of check configurations""" + + return load_beman_standard_config(".beman-standard.yml") From 429c99e6dcc9e5a6d1a2fe3212e20ea191699bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 10:25:19 +0300 Subject: [PATCH 134/371] Trim whitespace --- tools/beman-tidy/tests/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/__init__.py b/tools/beman-tidy/tests/__init__.py index b8a67863..1a94736f 100644 --- a/tools/beman-tidy/tests/__init__.py +++ b/tools/beman-tidy/tests/__init__.py @@ -1,3 +1,3 @@ """ Test package for beman-tidy. -""" \ No newline at end of file +""" From e784dd9ac40caef351accbfecb44465a21a283b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 10:28:49 +0300 Subject: [PATCH 135/371] beman-tidy: lint fix on .beman-standard.yml --- tools/beman-tidy/.beman-standard.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/.beman-standard.yml index 3d9ae6d3..7d1454fe 100644 --- a/tools/beman-tidy/.beman-standard.yml +++ b/tools/beman-tidy/.beman-standard.yml @@ -1,3 +1,4 @@ +# LICENSE LICENSE.APPROVED: - type: REQUIREMENT - licenses: @@ -15,6 +16,7 @@ LICENSE.APACHE_LLVM: LICENSE.CRITERIA: - type: REQUIREMENT +# GENERAL LIBRARY.NAMES: - type: RECOMMENDATION - regex: @@ -27,13 +29,14 @@ REPOSITORY.CODEOWNERS: REPOSITORY.DISALLOW_GIT_SUBMODULES: - type: RECOMMENDATION +# RELEASE RELEASE.GITHUB: - type: REQUIREMENT RELEASE.NOTES: - type: RECOMMENDATION RELEASE.GODBOLT_TRUNK_VERSION: - type: RECOMMENDATION - +# TOP LEVEL TOPLEVEL.CMAKE: - type: RECOMMENDATION - file_name: CMakeLists.txt @@ -44,6 +47,7 @@ TOPLEVEL.README: - type: RECOMMENDATION - file_name: README.md +# README README.TITLE: - type: RECOMMENDATION README.BADGES: @@ -67,6 +71,7 @@ README.LIBRARY_STATUS: "**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)", ] +# CMAKE CMAKE.DEFAULT: - type: RECOMMENDATION CMAKE.USE_FETCH_CONTENT: @@ -96,6 +101,7 @@ CMAKE.SKIP_EXAMPLES: CMAKE.AVOID_PASSTHROUGHS: - type: RECOMMENDATION +# DIRECTORY DIRECTORY.INTERFACE_HEADERS: - type: RECOMMENDATION - directory_name: include @@ -123,7 +129,7 @@ DIRECTORY.PAPERS: - type: RECOMMENDATION - directory_name: papers - +# FILE FILE.CPP_NAMES: - type: RECOMMENDATION - regex: @@ -141,6 +147,7 @@ FILE.COPYRIGHT: - type: RECOMMENDATION - regex: +# CPP CPP.NAMESPACE: - type: RECOMMENDATION CPP.NO_FLAG_FORKING: From 19bdbde21b6d35f11e7aa0c9e67fcf4956f513e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 10:34:52 +0300 Subject: [PATCH 136/371] beman-tidy: add Makefile --- tools/beman-tidy/Makefile | 13 +++++++++++++ tools/beman-tidy/README.md | 12 +++++++++--- tools/beman-tidy/requirements-dev.txt | 5 +++++ tools/beman-tidy/requirements.txt | 1 - 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100755 tools/beman-tidy/Makefile create mode 100644 tools/beman-tidy/requirements-dev.txt diff --git a/tools/beman-tidy/Makefile b/tools/beman-tidy/Makefile new file mode 100755 index 00000000..0ed14652 --- /dev/null +++ b/tools/beman-tidy/Makefile @@ -0,0 +1,13 @@ +# Default target: install and run tests. +all: install test + +# Install tool: +install: + pip3 install -r requirements.txt + +install-dev: + pip3 install -r requirements-dev.txt + +# Run tests: +test: + python3 -m pytest tests/ -v diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 8d3b0db7..edb33906 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -11,6 +11,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ## Installation ```shell +$ make install +# or $ pip3 install -r requirements.txt ``` @@ -80,12 +82,16 @@ Coverage: 17.78% (8/45 checks passed). Run the tests: ```shell -$ python3.9 -m pytest tests/ -v +$ make install-dev +pip3 install -r requirements-dev.txt +...q +$ make test +python3 -m pytest tests/ -v ========================================================================================================= test session starts ========================================================================================================= -platform darwin -- Python 3.9.6, pytest-8.4.0, pluggy-1.6.0 -- /Library/Developer/CommandLineTools/usr/bin/python3.9 +platform darwin -- Python 3.9.6, pytest-8.4.0, pluggy-1.6.0 -- /Library/Developer/CommandLineTools/usr/bin/python3 cachedir: .pytest_cache rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy -collected 3 items +collected 3 items tests/beman_standard/readme/test_readme.py::test_valid_readme_title PASSED [ 33%] tests/beman_standard/readme/test_readme.py::test_invalid_readme_title PASSED [ 66%] diff --git a/tools/beman-tidy/requirements-dev.txt b/tools/beman-tidy/requirements-dev.txt new file mode 100644 index 00000000..cbf5dcac --- /dev/null +++ b/tools/beman-tidy/requirements-dev.txt @@ -0,0 +1,5 @@ +GitPython==3.1.44 +Markdown==3.4.4 +Requests==2.32.3 +pyyaml==6.0.2 +pytest==8.4.0 diff --git a/tools/beman-tidy/requirements.txt b/tools/beman-tidy/requirements.txt index cbf5dcac..65b6c5cd 100644 --- a/tools/beman-tidy/requirements.txt +++ b/tools/beman-tidy/requirements.txt @@ -2,4 +2,3 @@ GitPython==3.1.44 Markdown==3.4.4 Requests==2.32.3 pyyaml==6.0.2 -pytest==8.4.0 From f250e8c67d71d5444e9caa359c3cca1928ef22a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 10:53:32 +0300 Subject: [PATCH 137/371] beman-tidy: cleanup docs --- tools/beman-tidy/tests/__init__.py | 3 --- tools/beman-tidy/tests/beman_standard/__init__.py | 3 --- tools/beman-tidy/tests/beman_standard/readme/__init__.py | 3 --- 3 files changed, 9 deletions(-) diff --git a/tools/beman-tidy/tests/__init__.py b/tools/beman-tidy/tests/__init__.py index 1a94736f..e69de29b 100644 --- a/tools/beman-tidy/tests/__init__.py +++ b/tools/beman-tidy/tests/__init__.py @@ -1,3 +0,0 @@ -""" -Test package for beman-tidy. -""" diff --git a/tools/beman-tidy/tests/beman_standard/__init__.py b/tools/beman-tidy/tests/beman_standard/__init__.py index e05ac54f..e69de29b 100644 --- a/tools/beman-tidy/tests/beman_standard/__init__.py +++ b/tools/beman-tidy/tests/beman_standard/__init__.py @@ -1,3 +0,0 @@ -""" -Tests for Beman Standard checks. -""" diff --git a/tools/beman-tidy/tests/beman_standard/readme/__init__.py b/tools/beman-tidy/tests/beman_standard/readme/__init__.py index 1cc026ee..e69de29b 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/__init__.py +++ b/tools/beman-tidy/tests/beman_standard/readme/__init__.py @@ -1,3 +0,0 @@ -""" -Tests for README checks. -""" From 668ed538f2e3b1514d7849998832d0a0253d33ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 10:54:53 +0300 Subject: [PATCH 138/371] beman-tidy: cleanup install scripts --- tools/beman-tidy/requirements-dev.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/beman-tidy/requirements-dev.txt b/tools/beman-tidy/requirements-dev.txt index cbf5dcac..69d461f3 100644 --- a/tools/beman-tidy/requirements-dev.txt +++ b/tools/beman-tidy/requirements-dev.txt @@ -1,5 +1 @@ -GitPython==3.1.44 -Markdown==3.4.4 -Requests==2.32.3 -pyyaml==6.0.2 pytest==8.4.0 From 9cac51658ba71ce8a3588cbecb552877bb11cc58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 10:59:45 +0300 Subject: [PATCH 139/371] beman-tidy: enable tests on CI --- .github/workflows/beman-tidy.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/beman-tidy.yml diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml new file mode 100644 index 00000000..7327ab05 --- /dev/null +++ b/.github/workflows/beman-tidy.yml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: Run Beman Tidy Tests + +# Run the tests for the beman-tidy tool. +on: + workflow_dispatch: + pull_request: + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies (production) + run: | + make -C tools/beman-tidy install + + - name: Install dependencies (development) + run: | + make -C tools/beman-tidy install-dev + + - name: Run tests + run: | + make -C tools/beman-tidy test From feb9794968df89204581c6fbeacd014594285397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 11:03:14 +0300 Subject: [PATCH 140/371] beman-tidy: cleanup docs --- tools/beman-tidy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index edb33906..d27831d5 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -1,4 +1,4 @@ -# beman-tidy: Codebase Bemanification Tool +# beman-tidy: The Codebase Bemanification Tool + + +![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) + 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. -Note: Other checks are not run for this test!!! +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 license is properly formatted. diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py index f827914f..0c62615e 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -3,7 +3,7 @@ import pytest from pathlib import Path -from lib.checks.beman_standard.readme import ReadmeTitleCheck +from lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck def test__README_TITLE__valid(repo_info, beman_standard_check_config, valid_readme_path): @@ -37,3 +37,28 @@ def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config, inva assert check_instance.default_check() is True assert check_instance.check() is True + + +def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_readme_path): + """Test that a valid README.md badges passes the check""" + check_instance = ReadmeBadgesCheck(repo_info, beman_standard_check_config) + check_instance.path = valid_readme_path + check_instance.log_enabled = True + + assert check_instance.default_check() is True + assert check_instance.check() is True + + +def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid_readme_path): + """Test that an invalid README.md badges fails the check""" + check_instance = ReadmeBadgesCheck(repo_info, beman_standard_check_config) + check_instance.path = invalid_readme_path + + assert check_instance.default_check() is True + assert check_instance.check() is False + + +@pytest.mark.skip(reason="NOT implemented") +def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): + """Test that the fix method corrects an invalid README.md badges""" + pass From 79035b1998130a3b0bab8e0e729b5e39de4b2d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 19:43:19 +0300 Subject: [PATCH 153/371] beman-tidy: add todos --- .../beman-tidy/lib/checks/beman_standard/readme.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index b6b11729..aef62e39 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -6,12 +6,6 @@ from ...utils.git import * from ..system.registry import register_beman_standard_check -# TODO README.TITLE -# TODO README.BADGES -# TODO README.PURPOSE -# TODO README.IMPLEMENTS -# TODO README.LIBRARY_STATUS - class ReadmeBaseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): @@ -68,3 +62,11 @@ def check(self): self.log( f"The file '{self.path}' does not contain any of the required badges: {values}") return False + +# TODO README.PURPOSE + + +# TODO README.IMPLEMENTS + + +# TODO README.LIBRARY_STATUS From 9820a09481f8a9e477984aef00678cf1ca4902bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 20:45:43 +0300 Subject: [PATCH 154/371] beman-tidy: add README.LIBRARY_STATUS --- tools/beman-tidy/.beman-standard.yml | 2 +- .../lib/checks/base/file_base_check.py | 10 ++ .../lib/checks/beman_standard/readme.py | 53 +++++--- .../readme/data/invalid/invalid-badge-v1.md | 16 +++ .../readme/data/invalid/invalid-badge-v2.md | 17 +++ .../readme/data/invalid/invalid-badge-v3.md | 16 +++ .../data/invalid/invalid-status-line-v1.md | 14 +++ .../data/invalid/invalid-status-line-v2.md | 15 +++ .../data/invalid/invalid-status-line-v3.md | 18 +++ .../readme/data/invalid/invalid-title-v1.md | 15 +++ .../readme/data/invalid/invalid-title-v2.md | 16 +++ .../readme/data/invalid/invalid-title-v3.md | 16 +++ .../readme/data/invalid/invalid-title-v4.md | 16 +++ .../data/invalid/{README.md => invalid.md} | 6 +- .../readme/data/valid/README-v1.md | 25 ++++ .../readme/data/valid/README-v2.md | 24 ++++ .../readme/data/valid/README-v3.md | 24 ++++ .../readme/data/valid/README-v4.md | 24 ++++ .../readme/data/valid/README.md | 12 -- .../beman_standard/readme/test_readme.py | 119 +++++++++++++----- .../tests/utils/directory_testcase_runners.py | 0 .../tests/utils/file_testcase_runners.py | 64 ++++++++++ 22 files changed, 458 insertions(+), 64 deletions(-) create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v1.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v2.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v3.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v1.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v2.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v3.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v4.md rename tools/beman-tidy/tests/beman_standard/readme/data/invalid/{README.md => invalid.md} (52%) create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v1.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v2.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v3.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v4.md delete mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md create mode 100644 tools/beman-tidy/tests/utils/directory_testcase_runners.py create mode 100644 tools/beman-tidy/tests/utils/file_testcase_runners.py diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/.beman-standard.yml index 7e4aa7f2..0feee03c 100644 --- a/tools/beman-tidy/.beman-standard.yml +++ b/tools/beman-tidy/.beman-standard.yml @@ -69,7 +69,7 @@ README.IMPLEMENTS: - type: RECOMMENDATION README.LIBRARY_STATUS: - type: RECOMMENDATION - - status_lines: [ + - 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)", diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index 39016ebb..83756f19 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -3,6 +3,7 @@ from .base_check import BaseCheck import os +import re import sys @@ -93,3 +94,12 @@ def is_empty(self): Check if the file is empty. """ return len(self.read()) == 0 + + def has_content(self, content_to_match): + """ + Check if the file contains the given content (literal string match). + """ + readme_content = self.read() + if not readme_content or len(readme_content) == 0: + return False + return re.search(re.escape(content_to_match), readme_content) is not None diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index aef62e39..6d0f2644 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -21,12 +21,11 @@ def check(self): lines = self.read_lines_strip() first_line = lines[0] - # Match the pattern "# [: ]" - regex = r"^# (beman\.[a-zA-Z0-9_]+)(: (.*))?$" - match = re.match(regex, first_line) - if not match: + # Match the pattern "# [: ]" + regex = rf"^# {re.escape(self.library_name)}: (.*)$" # noqa: F541 + if not re.match(regex, first_line): self.log( - f"The first line of the file '{self.path}' is invalid. It should start with '# [: ]'.") + f"The first line of the file '{self.path}' is invalid. It should start with '# {self.library_name}: '.") return False return True @@ -47,21 +46,21 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): """ - self.config["values"] contains a fixed set of Bemanba badges. + self.config["values"] contains a fixed set of Beman badges. """ - readme_content = self.read() + badges = self.config["values"] + assert len(badges) == 4 # The number of library maturity model states - values = self.config["values"] - assert len(values) == 4 # The number of library maturity model states + # Check if at 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 - # Check if at least one of the required badges is present. - for value in values: - if re.search(re.escape(value), readme_content): - return True + return True - self.log( - f"The file '{self.path}' does not contain any of the required badges: {values}") - return False # TODO README.PURPOSE @@ -70,3 +69,25 @@ def check(self): # TODO 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) + + def check(self): + """ + self.config["values"] contains a fixed set of Beman library statuses. + """ + statuses = self.config["values"] + # The number of library maturity model states + assert len(statuses) == 4 + + # Check if at least one of the required status values is present. + status_count = len( + [status for status in statuses if self.has_content(status)]) + if status_count != 1: + self.log( + f"The file '{self.path}' does not contain exactly one of the required statuses from {statuses}") + return False + + return True diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v1.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v1.md new file mode 100644 index 00000000..c2a3c135 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v1.md @@ -0,0 +1,16 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![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) + +**Purpose**: `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: typos in badges. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v2.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v2.md new file mode 100644 index 00000000..ec8f9cee --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v2.md @@ -0,0 +1,17 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![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) + +**Purpose**: `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: invalid badge display text. + + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v3.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v3.md new file mode 100644 index 00000000..dfdd4e2f --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v3.md @@ -0,0 +1,16 @@ +# beman.exemplar: A Beman Library Exemplar + + + + +![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) + +**Purpose**: `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: invalid badge URL. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md new file mode 100644 index 00000000..aa46bddb --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md @@ -0,0 +1,14 @@ +## 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) + +**Purpose**: `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. + +This is NOT a valid README.md according to the Beman Standard: the library status is not properly formatted. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md new file mode 100644 index 00000000..6d3f668f --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.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) + +**Purpose**: `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) + +This is NOT a valid README.md according to the Beman Standard: the library status line has typos. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md new file mode 100644 index 00000000..af1629a1 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md @@ -0,0 +1,18 @@ +# 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) + +**Purpose**: `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), + +This is NOT a valid README.md according to the Beman Standard: the library status is duplicated. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v1.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v1.md new file mode 100644 index 00000000..573d65b4 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v1.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) + +**Purpose**: `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: missing beman.exemplar. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v2.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v2.md new file mode 100644 index 00000000..b992d38e --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v2.md @@ -0,0 +1,16 @@ +# 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) + +**Purpose**: `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: missing : + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v3.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v3.md new file mode 100644 index 00000000..0f4eda26 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v3.md @@ -0,0 +1,16 @@ +# beman.optional: C++26 Optional Library + + + + +![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) + +**Purpose**: `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: wrong library name. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v4.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v4.md new file mode 100644 index 00000000..0f4eda26 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v4.md @@ -0,0 +1,16 @@ +# beman.optional: C++26 Optional Library + + + + +![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) + +**Purpose**: `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: wrong library name. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid.md similarity index 52% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md rename to tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid.md index 19514fb3..7048d188 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/README.md +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid.md @@ -1,7 +1,11 @@ # Wrong Title Format -This is an invalid README.md file that doesn't follow the Beman Standard: the title doesn't include the library name in the correct format. +This is an invalid README.md file that doesn't follow the Beman Standard: the title doesn't have the correct format. This is an invalid README.md file that doesn't follow the Beman Standard: the badges are missing. +This is an invalid README.md file that doesn't follow the Beman Standard: the purpose is missing. + +This is an invalid README.md file that doesn't follow the Beman Standard: the library status is missing. + This is an invalid README.md file that doesn't follow the Beman Standard: the license is missing. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v1.md b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v1.md new file mode 100644 index 00000000..35bab355 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v1.md @@ -0,0 +1,25 @@ +# 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) + +**Purpose**: `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. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v2.md b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v2.md new file mode 100644 index 00000000..5f79a535 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v2.md @@ -0,0 +1,24 @@ +# beman.exemplar: Another Beman Library + + + + +![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) + +**Purpose**: `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) + +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. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v3.md b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v3.md new file mode 100644 index 00000000..e341a6b4 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v3.md @@ -0,0 +1,24 @@ +# beman.exemplar: Awesome Beman Library + + + + +![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) + +**Purpose**: `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) + +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. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v4.md b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v4.md new file mode 100644 index 00000000..ae00d264 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v4.md @@ -0,0 +1,24 @@ +# beman.exemplar: The Most Awesome Beman Library + + + + +![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) + +**Purpose**: `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) + +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. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md b/tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md deleted file mode 100644 index d86bfb9f..00000000 --- a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# beman.examplar: 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) - -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 license is properly formatted. diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py index 0c62615e..129fbdf9 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -3,62 +3,113 @@ import pytest from pathlib import Path -from lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck +from lib.checks.beman_standard.readme import * +from tests.utils.file_testcase_runners import * -def test__README_TITLE__valid(repo_info, beman_standard_check_config, valid_readme_path): +def test__README_TITLE__valid(repo_info, beman_standard_check_config): """Test that a valid README.md title passes the check""" - check_instance = ReadmeTitleCheck(repo_info, beman_standard_check_config) - check_instance.path = valid_readme_path - - assert check_instance.default_check() is True - assert check_instance.check() is True - - -def test__README_TITLE__invalid(repo_info, beman_standard_check_config, invalid_readme_path): + valid_readme_paths = [ + # Title: # beman.exemplar: A Beman Library Exemplar + Path("tests/beman_standard/readme/data/valid/README-v1.md"), + # Title: # beman.exemplar: Another Beman Library + Path("tests/beman_standard/readme/data/valid/README-v2.md"), + # Title: # beman.exemplar: Awesome Beman Library + Path("tests/beman_standard/readme/data/valid/README-v3.md"), + # Title: # beman.exemplar: The Most Awesome Beman Library + Path("tests/beman_standard/readme/data/valid/README-v4.md"), + ] + + file_testcases_run_valid(valid_readme_paths, ReadmeTitleCheck, + 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""" - check_instance = ReadmeTitleCheck(repo_info, beman_standard_check_config) - check_instance.path = invalid_readme_path + invalid_readme_paths = [ + Path("tests/beman_standard/readme/data/invalid/invalid.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v1.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v2.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v3.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v4.md"), + ] - assert check_instance.default_check() is True - assert check_instance.check() is False + file_testcases_run_invalid(invalid_readme_paths, ReadmeTitleCheck, + repo_info, beman_standard_check_config) -def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): +def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): """Test that the fix method corrects an invalid README.md title""" - check_instance = ReadmeTitleCheck(repo_info, beman_standard_check_config) - check_instance.path = f"{invalid_readme_path}.delete_me" - check_instance.write(invalid_readme_path.read_text()) - - assert check_instance.default_check() is True - assert check_instance.check() is False + invalid_readme_paths = [ + Path("tests/beman_standard/readme/data/invalid/invalid-title-v1.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v2.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v3.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-title-v4.md"), + ] - assert check_instance.fix() is True - - assert check_instance.default_check() is True - assert check_instance.check() is True + file_testcases_run_fix_invalid( + invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config) def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_readme_path): """Test that a valid README.md badges passes the check""" - check_instance = ReadmeBadgesCheck(repo_info, beman_standard_check_config) - check_instance.path = valid_readme_path - check_instance.log_enabled = True + valid_readme_paths = [ + Path("tests/beman_standard/readme/data/valid/README-v1.md"), + Path("tests/beman_standard/readme/data/valid/README-v2.md"), + Path("tests/beman_standard/readme/data/valid/README-v3.md"), + Path("tests/beman_standard/readme/data/valid/README-v4.md"), + ] - assert check_instance.default_check() is True - assert check_instance.check() is True + file_testcases_run_valid(valid_readme_paths, ReadmeBadgesCheck, + repo_info, beman_standard_check_config) def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid_readme_path): """Test that an invalid README.md badges fails the check""" - check_instance = ReadmeBadgesCheck(repo_info, beman_standard_check_config) - check_instance.path = invalid_readme_path + invalid_readme_paths = [ + Path("tests/beman_standard/readme/data/invalid/invalid.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-badge-v1.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-badge-v2.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-badge-v3.md"), + ] - assert check_instance.default_check() is True - assert check_instance.check() is False + file_testcases_run_invalid(invalid_readme_paths, ReadmeBadgesCheck, + repo_info, beman_standard_check_config) @pytest.mark.skip(reason="NOT implemented") def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): """Test that the fix method corrects an invalid README.md badges""" pass + + +def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config, valid_readme_path): + """Test that a valid README.md library status passes the check""" + valid_readme_paths = [ + Path("tests/beman_standard/readme/data/valid/README-v1.md"), + Path("tests/beman_standard/readme/data/valid/README-v2.md"), + Path("tests/beman_standard/readme/data/valid/README-v3.md"), + Path("tests/beman_standard/readme/data/valid/README-v4.md"), + ] + + file_testcases_run_valid(valid_readme_paths, ReadmeLibraryStatusCheck, + 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""" + invalid_readme_paths = [ + Path("tests/beman_standard/readme/data/invalid/invalid.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md"), + ] + + file_testcases_run_invalid(invalid_readme_paths, ReadmeLibraryStatusCheck, + repo_info, beman_standard_check_config) + + +@pytest.mark.skip(reason="NOT implemented") +def test__README_LIBRARY_STATUS__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): + """Test that the fix method corrects an invalid README.md library status""" + pass diff --git a/tools/beman-tidy/tests/utils/directory_testcase_runners.py b/tools/beman-tidy/tests/utils/directory_testcase_runners.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py new file mode 100644 index 00000000..828eb081 --- /dev/null +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import os + + +def file_testcase_run(file_path, check_class, repo_info, beman_standard_check_config, expected_result): + check_instance = check_class(repo_info, beman_standard_check_config) + check_instance.path = file_path + check_instance.log_level = True + + assert check_instance.default_check( + ) is True, f"Default check failed for {file_path}" + assert check_instance.check( + ) is expected_result, f"Check failed for {file_path}" + + +def file_testcase_run_valid(file_path, check_class, repo_info, beman_standard_check_config): + file_testcase_run(file_path, check_class, repo_info, + beman_standard_check_config, True) + + +def file_testcase_run_invalid(file_path, check_class, repo_info, beman_standard_check_config): + file_testcase_run(file_path, check_class, repo_info, + beman_standard_check_config, False) + + +def file_testcase_run_fix_invalid(invalid_file_path, check_class, repo_info, beman_standard_check_config): + check_instance = check_class(repo_info, beman_standard_check_config) + check_instance.path = f"{invalid_file_path}.delete_me" + check_instance.write(invalid_file_path.read_text()) + + assert check_instance.default_check() is True + assert check_instance.check() is False + + assert check_instance.fix() is True + + assert check_instance.default_check() is True + assert check_instance.check() is True + + # Delete the temporary file + os.remove(f"{invalid_file_path}.delete_me") + + +def file_testcases_run(file_paths, check_class, repo_info, beman_standard_check_config, expected_result): + for file_path in file_paths: + file_testcase_run(file_path, check_class, repo_info, + beman_standard_check_config, expected_result) + + +def file_testcases_run_valid(file_paths, check_class, repo_info, beman_standard_check_config): + file_testcases_run(file_paths, check_class, repo_info, + beman_standard_check_config, True) + + +def file_testcases_run_invalid(file_paths, check_class, repo_info, beman_standard_check_config): + file_testcases_run(file_paths, check_class, repo_info, + beman_standard_check_config, False) + + +def file_testcases_run_fix_invalid(invalid_file_paths, check_class, repo_info, beman_standard_check_config): + for invalid_file_path in invalid_file_paths: + file_testcase_run_fix_invalid( + invalid_file_path, check_class, repo_info, beman_standard_check_config) From 466a0dc489cbd73f622e79caf3a9f98c7317fe32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 20:47:08 +0300 Subject: [PATCH 155/371] beman-tidy: add TODOs in testing framework for directories --- tools/beman-tidy/tests/utils/directory_testcase_runners.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/beman-tidy/tests/utils/directory_testcase_runners.py b/tools/beman-tidy/tests/utils/directory_testcase_runners.py index e69de29b..9b1d2853 100644 --- a/tools/beman-tidy/tests/utils/directory_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/directory_testcase_runners.py @@ -0,0 +1,4 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# TODO: Implement directory testcase runners From 04b39b300cd8a1a0145ebf0de9ead02e01c85e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 20:54:27 +0300 Subject: [PATCH 156/371] beman-tidy: update docs with summray and verbose snippets --- tools/beman-tidy/README.md | 46 +++++++++++++------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index d30993a2..c4bce278 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -41,47 +41,31 @@ optional arguments: * Run beman-tidy on the exemplar repository (default: dry-run mode) ```shell -$ ./beman-tidy ../exemplar --verbose -beman-tidy started ... +# non-verbose mode +$ ./beman-tidy ../../../exemplar +Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). -Running check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... - check [REQUIREMENT][TOPLEVEL.CHANGELOG] ... PASSED +Coverage: 6.98% (3/43 checks passed). -Running check [REQUIREMENT][TOPLEVEL.CMAKE] ... - check [REQUIREMENT][TOPLEVEL.CMAKE] ... PASSED - -Running check [REQUIREMENT][TOPLEVEL.LICENSE] ... - check [REQUIREMENT][TOPLEVEL.LICENSE] ... PASSED - -Running check [REQUIREMENT][TOPLEVEL.README] ... - check [REQUIREMENT][TOPLEVEL.README] ... PASSED - -Running check [REQUIREMENT][CHANGELOG.TITLE] ... - check [REQUIREMENT][CHANGELOG.TITLE] ... PASSED - -Running check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... - check [REQUIREMENT][CHANGELOG.LIBRARY_STATUS] ... PASSED +# verbose mode +$ ./beman-tidy ../../../exemplar --verbose +beman-tidy pipeline started ... Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... FAILED - -Running check [REQUIREMENT][README.BADGES] ... -[ERROR ][README.BADGES ]: Only one line of badges is allowed. -[ERROR ][README.BADGES ]: First line of README.md must contain badges. - check [REQUIREMENT][README.BADGES] ... FAILED + check [RECOMMENDATION][README.TITLE] ... PASSED -Running check [RECOMMENDATION][README.IMPLEMENTS] ... - check [RECOMMENDATION][README.IMPLEMENTS] ... PASSED +Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [REQUIREMENT][README.LIBRARY_STATUS] ... - check [REQUIREMENT][README.LIBRARY_STATUS] ... PASSED +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED -beman-tidy finished. +beman-tidy pipeline finished. -Summary: 8 checks PASSED, 2 checks FAILED, 35 skipped (not implemented). +Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). -Coverage: 17.78% (8/45 checks passed). +Coverage: 6.98% (3/43 checks passed). ``` * Run beman-tidy on the exemplar repository (fix issues in-place): From 68ac2629ef949554f521fc516598382877c083d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 20:59:46 +0300 Subject: [PATCH 157/371] beman-tidy: update docs with screenshot for usage example --- tools/beman-tidy/README.md | 2 ++ tools/beman-tidy/images/usage-example.png | Bin 0 -> 63057 bytes 2 files changed, 2 insertions(+) create mode 100644 tools/beman-tidy/images/usage-example.png diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index c4bce278..ac74bedd 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -21,6 +21,8 @@ $ pip3 install -r requirements.txt ## Usage +![beman-tidy usage example](./images/usage-example.png) + * Display help: ```shell $ ./beman-tidy --help diff --git a/tools/beman-tidy/images/usage-example.png b/tools/beman-tidy/images/usage-example.png new file mode 100644 index 0000000000000000000000000000000000000000..957fe8fe67c47ec8a7fa2d4b55e547aa633e930f GIT binary patch literal 63057 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 literal 0 HcmV?d00001 From d592ae3c282e4371532ff8fe663ac2d684a4c7d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 21:01:03 +0300 Subject: [PATCH 158/371] Add .markdownlintignore --- tools/beman-tidy/.markdownlintignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/beman-tidy/.markdownlintignore diff --git a/tools/beman-tidy/.markdownlintignore b/tools/beman-tidy/.markdownlintignore new file mode 100644 index 00000000..2bfa6a4d --- /dev/null +++ b/tools/beman-tidy/.markdownlintignore @@ -0,0 +1 @@ +tests/ From 53046fb8a59b09aac8d4c11b1097eeda11dc3463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sat, 7 Jun 2025 21:12:17 +0300 Subject: [PATCH 159/371] beman-tidy: update docs with example failing checks --- tools/beman-tidy/README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index ac74bedd..86e3b668 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -49,7 +49,7 @@ Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). Coverage: 6.98% (3/43 checks passed). -# verbose mode +# verbose mode - no errors $ ./beman-tidy ../../../exemplar --verbose beman-tidy pipeline started ... @@ -68,6 +68,27 @@ beman-tidy pipeline finished. Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). Coverage: 6.98% (3/43 checks passed). + +# verbose mode - with errors +$ ./beman-tidy ../../../exemplar --verbose +beman-tidy pipeline started ... + +Running check [RECOMMENDATION][README.TITLE] ... +[WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. + check [RECOMMENDATION][README.TITLE] ... FAILED + +Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED + +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + + +beman-tidy pipeline finished. + +Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). + +Coverage: 4.65% (2/43 checks passed). ``` * Run beman-tidy on the exemplar repository (fix issues in-place): From 6b77b3f9157cc4876fb804e75522345ecd31152e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 9 Jun 2025 10:43:33 +0300 Subject: [PATCH 160/371] beman-tidy: remove import * --- tools/beman-tidy/Makefile | 4 +-- tools/beman-tidy/beman-tidy | 13 ++++++--- .../beman-tidy/lib/checks/base/base_check.py | 2 +- .../lib/checks/beman_standard/readme.py | 4 +-- .../lib/checks/beman_standard/release.py | 2 -- .../lib/checks/beman_standard/toplevel.py | 1 - tools/beman-tidy/lib/checks/system/git.py | 4 +-- tools/beman-tidy/lib/pipeline.py | 29 ++++++++++--------- tools/beman-tidy/lib/utils/git.py | 1 - .../tests/beman_standard/readme/conftest.py | 1 + .../beman_standard/readme/test_readme.py | 6 ++-- 11 files changed, 37 insertions(+), 30 deletions(-) diff --git a/tools/beman-tidy/Makefile b/tools/beman-tidy/Makefile index 503663e1..9b06e6a7 100755 --- a/tools/beman-tidy/Makefile +++ b/tools/beman-tidy/Makefile @@ -25,10 +25,10 @@ test: self-lint: @echo "Running linter..." @pwd - find . -name "*.py" | xargs autopep8 --exit-code --diff + find . -name "*.py" -or -name "beman-tidy" | xargs autopep8 --exit-code --diff # Run lint-fix: self-lint-fix: @echo "Running linter-fix..." @pwd - find . -name "*.py" | xargs autopep8 --in-place + find . -name "*.py" -or -name "beman-tidy" | xargs autopep8 --in-place diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 64bdddea..4a6d869a 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,8 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse -from lib.utils.git import * -from lib.pipeline import * + +from lib.utils.git import get_repo_info, load_beman_standard_config +from lib.pipeline import run_checks_pipeline + def parse_args(): """ @@ -33,14 +35,17 @@ def main(): """ args = parse_args() - beman_standard_check_config = load_beman_standard_config(".beman-standard.yml") + beman_standard_check_config = load_beman_standard_config( + ".beman-standard.yml") if not beman_standard_check_config or len(beman_standard_check_config) == 0: print("Failed to download the beman standard. STOP.") return - checks_to_run = [check for check in beman_standard_check_config] if args.checks is None else args.checks + checks_to_run = [ + check for check in beman_standard_check_config] if args.checks is None else args.checks run_checks_pipeline(checks_to_run, args, beman_standard_check_config) + if __name__ == "__main__": main() diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 13026699..215f3d1c 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -3,7 +3,7 @@ import os import sys -from ..system.registry import * +from ..system.registry import get_beman_standard_check_name_by_class class BaseCheck(object): diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 6d0f2644..4a7ec2c0 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -1,9 +1,9 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import re + from ..base.file_base_check import FileBaseCheck -from ...utils.string import * -from ...utils.git import * from ..system.registry import register_beman_standard_check diff --git a/tools/beman-tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/lib/checks/beman_standard/release.py index 14ea5c91..e2e13e48 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/lib/checks/beman_standard/release.py @@ -2,8 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.file_base_check import FileBaseCheck -from ...utils.string import * -from ...utils.git import * # TODO RELEASE.GITHUB # TODO RELEASE.NOTES diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 6c20ecb1..289e6175 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.file_base_check import FileBaseCheck -from ...utils.git import * # TODO TOPLEVEL.CMAKE # TODO TOPLEVEL.LICENSE diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/lib/checks/system/git.py index 9aadcd3c..31161b17 100644 --- a/tools/beman-tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/lib/checks/system/git.py @@ -1,10 +1,10 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.base_check import BaseCheck - import sys +from ..base.base_check import BaseCheck + class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): """ diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 2602c8a3..9406f0af 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -1,18 +1,21 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from .checks.system.registry import * - -from .checks.system.git import * -from .checks.beman_standard.cmake import * -from .checks.beman_standard.cpp import * -from .checks.beman_standard.directory import * -from .checks.beman_standard.file import * -from .checks.beman_standard.general import * -from .checks.beman_standard.license import * -from .checks.beman_standard.readme import * -from .checks.beman_standard.release import * -from .checks.beman_standard.toplevel import * +import sys + +from .checks.system.registry import get_registered_beman_standard_checks +from .checks.system.git import DisallowFixInplaceAndUnstagedChangesCheck + +# Import all the implemented checks. +# from .checks.beman_standard.cmake import +# from .checks.beman_standard.cpp import +# from .checks.beman_standard.directory import +# from .checks.beman_standard.file import +# from .checks.beman_standard.general import +# from .checks.beman_standard.license import +from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck +# from .checks.beman_standard.release import +# from .checks.beman_standard.toplevel import red_color = "\033[91m" green_color = "\033[92m" @@ -28,7 +31,7 @@ def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): Verbosity is controlled by args.verbose. """ - """ + """ Helper function to log messages. """ def log(msg): diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 73de4541..9811fe06 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -4,7 +4,6 @@ import os import sys import yaml - from git import Repo, InvalidGitRepositoryError diff --git a/tools/beman-tidy/tests/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/beman_standard/readme/conftest.py index 5f922522..28be98cc 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/beman_standard/readme/conftest.py @@ -4,6 +4,7 @@ import os import pytest from pathlib import Path + from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py index 129fbdf9..7e7f5d18 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -3,8 +3,10 @@ import pytest from pathlib import Path -from lib.checks.beman_standard.readme import * -from tests.utils.file_testcase_runners import * + +from tests.utils.file_testcase_runners import file_testcases_run_valid, file_testcases_run_invalid, file_testcases_run_fix_invalid +# Actual tested checks. +from lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck def test__README_TITLE__valid(repo_info, beman_standard_check_config): From 8af9996ba10b87c1cad49bc5117b454d7d8821ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 9 Jun 2025 10:44:06 +0300 Subject: [PATCH 161/371] beman-tidy: fix typo in docs --- tools/beman-tidy/lib/checks/beman_standard/readme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 4a7ec2c0..d6bbccab 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -51,7 +51,7 @@ def check(self): badges = self.config["values"] assert len(badges) == 4 # The number of library maturity model states - # Check if at exactly one of the required badges is present. + # 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: From 9a7bbb4fc0f1d74916fb2c711e8c03c86871d0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 9 Jun 2025 10:56:02 +0300 Subject: [PATCH 162/371] beman-tidy: make classes in checks/base/ to be abstract classes --- .../beman-tidy/lib/checks/base/base_check.py | 11 ++++---- .../lib/checks/base/directory_base_check.py | 27 +++++++++++++++++-- .../lib/checks/base/file_base_check.py | 20 ++++++++++++-- .../lib/checks/beman_standard/readme.py | 7 +++++ 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 215f3d1c..703beae0 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -1,12 +1,11 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -import os -import sys +from abc import ABC, abstractmethod from ..system.registry import get_beman_standard_check_name_by_class -class BaseCheck(object): +class BaseCheck(ABC): """ Base class for checks. This class is not meant to be used directly, it's meant to be subclassed. @@ -67,21 +66,23 @@ def default_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. """ - raise NotImplementedError(f"[{self.name}] check() not implemented.") + pass + @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. """ - return False + pass def log(self, message, enabled=True): """ diff --git a/tools/beman-tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/lib/checks/base/directory_base_check.py index b9a5476a..a37baa84 100644 --- a/tools/beman-tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/lib/checks/base/directory_base_check.py @@ -1,9 +1,10 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from .base_check import BaseCheck +from abc import ABC, abstractmethod import os -import sys + +from .base_check import BaseCheck class DirectoryBaseCheck(BaseCheck): @@ -18,6 +19,28 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): self.path = os.path.join(repo_info["top_level"], relative_path) def default_check(self): + """ + Override. + Checks if this rule is properly initialized. + """ + if not super().default_check(): + return False + + # TODO: Implement the default check. + pass + + @abstractmethod + def check(self): + """ + Override this method, make it abstract because this is style an abstract class. + """ + pass + + @abstractmethod + def fix(self): + """ + Override this method, make it abstract because this is style an abstract class. + """ pass # TODO: add methods to read the directory content diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index 83756f19..be5a0ac5 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -1,10 +1,11 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from .base_check import BaseCheck +from abc import ABC, abstractmethod import os import re -import sys + +from .base_check import BaseCheck class FileBaseCheck(BaseCheck): @@ -20,6 +21,7 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): def default_check(self): """ + Override. Checks if this rule is properly initialized. """ if not super().default_check(): @@ -39,6 +41,20 @@ def default_check(self): return True + @abstractmethod + def check(self): + """ + Override this method, make it abstract because this is style an abstract class. + """ + pass + + @abstractmethod + def fix(self): + """ + Override this method, make it abstract because this is style an abstract class. + """ + pass + def read(self): """ Read the file content. diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index d6bbccab..676ea43a 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -61,6 +61,9 @@ def check(self): return True + def fix(self): + # TODO: Implement the fix. + pass # TODO README.PURPOSE @@ -91,3 +94,7 @@ def check(self): return False return True + + def fix(self): + # TODO: Implement the fix. + pass From e295c1932d5d80c2ea2dc6e16e46c9346dbb0921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 9 Jun 2025 11:22:05 +0300 Subject: [PATCH 163/371] beman-tidy: add Beman Library Maturity Model info BaseCheck --- tools/beman-tidy/lib/checks/base/base_check.py | 6 ++++++ tools/beman-tidy/lib/checks/beman_standard/readme.py | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 703beae0..0ab8140b 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -48,6 +48,12 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): self.library_name = f"beman.{self.repo_name}" assert self.library_name is not None + # set beman library maturity model + beman_library_maturity_model = beman_standard_check_config["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 default_check(self): """ Checks if this rule is properly initialized. diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 676ea43a..84deacb5 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -82,8 +82,7 @@ def check(self): self.config["values"] contains a fixed set of Beman library statuses. """ statuses = self.config["values"] - # The number of library maturity model states - assert len(statuses) == 4 + assert len(statuses) == len(self.beman_library_maturity_model) # Check if at least one of the required status values is present. status_count = len( From 8fcf81c148a85dc625d89ad7a59736a8c1199be1 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 9 Jun 2025 11:33:55 -0400 Subject: [PATCH 164/371] Fix missing EOF at end of containers/install_sys.sh This is flagged by the pre-commit linter in exemplar. --- containers/install_sys.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/install_sys.sh b/containers/install_sys.sh index 272ab7bf..0e31aca4 100644 --- a/containers/install_sys.sh +++ b/containers/install_sys.sh @@ -7,4 +7,4 @@ echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://ap sudo apt-get update && sudo apt-get install -y cmake # Install Ninja -sudo apt-get install -y ninja-build \ No newline at end of file +sudo apt-get install -y ninja-build From 316ad3fc68af3c443751654e9a42242868f2bc39 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Wed, 30 Apr 2025 22:55:46 -0400 Subject: [PATCH 165/371] Add toolchain files and beman-submodule This pull request adds a new script, beman-submodule, which provides some of the features of git submodule but without git submodule's disadvantage that users need to be aware of it to clone the repository. More information can be found in tools/beman-submodule/README.md. It also pulls in the toolchain files from exemplar, preserving history, using a git filter-branch. --- .github/workflows/beman-submodule.yml | 30 ++ cmake/use-fetch-content.cmake | 2 +- tools/beman-submodule/README.md | 63 +++ tools/beman-submodule/beman-submodule | 212 +++++++++++ .../test/test_beman_submodule.py | 359 ++++++++++++++++++ 5 files changed, 665 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/beman-submodule.yml create mode 100644 tools/beman-submodule/README.md create mode 100755 tools/beman-submodule/beman-submodule create mode 100644 tools/beman-submodule/test/test_beman_submodule.py diff --git a/.github/workflows/beman-submodule.yml b/.github/workflows/beman-submodule.yml new file mode 100644 index 00000000..d18dd7fa --- /dev/null +++ b/.github/workflows/beman-submodule.yml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: beman-submodule tests + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + beman-submodule-script-ci: + name: beman_module.py ci + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.13 + + - name: Install pytest + run: | + python3 -m pip install pytest + + - name: Run pytest + run: | + cd tools/beman-submodule/ + pytest diff --git a/cmake/use-fetch-content.cmake b/cmake/use-fetch-content.cmake index a9130520..82c5db29 100644 --- a/cmake/use-fetch-content.cmake +++ b/cmake/use-fetch-content.cmake @@ -10,7 +10,7 @@ if(NOT BEMAN_EXEMPLAR_LOCKFILE) ) endif() -set(BemanExemplar_projectDir "${CMAKE_CURRENT_LIST_DIR}/..") +set(BemanExemplar_projectDir "${CMAKE_CURRENT_LIST_DIR}/../..") message(TRACE "BemanExemplar_projectDir=\"${BemanExemplar_projectDir}\"") message(TRACE "BEMAN_EXEMPLAR_LOCKFILE=\"${BEMAN_EXEMPLAR_LOCKFILE}\"") diff --git a/tools/beman-submodule/README.md b/tools/beman-submodule/README.md new file mode 100644 index 00000000..36883ada --- /dev/null +++ b/tools/beman-submodule/README.md @@ -0,0 +1,63 @@ +# beman-submodule + + + +## What is this script? + +`beman-submodule` provides some of the features of `git submodule`, adding child git +repositories to a parent git repository, but unlike with `git submodule`, the entire child +repo is directly checked in, so only maintainers, not users, need to run this script. The +command line interface mimics `git submodule`'s. + +## How do I add a beman submodule to my repository? + +The first beman submodule you should add is this repository, `infra/`, which you can +bootstrap by running: + + +```sh +curl -s https://raw.githubusercontent.com/bemanproject/infra/refs/heads/main/tools/beman-submodule/beman-submodule | python3 - add https://github.com/bemanproject/infra.git +``` + +Once that's added, you can run the script from `infra/tools/beman-submodule/beman-submodule`. + +## How do I update a beman submodule to the latest trunk? + +You can run `beman-submodule update --remote` to update all beman submodule to latest +trunk, or e.g. `beman-submodule update --remote infra` to update only a specific one. + +## How does it work under the hood? + +Along with the files from the child repository, it creates a dotfile called +`.beman_submodule`, which looks like this: + +```ini +[beman_submodule] +remote=https://github.com/bemanproject/infra.git +commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77 +``` + +## How do I update a beman submodule to a specific commit or change the remote URL? + +You can edit the corresponding lines in the `.beman_submodule` file and run +`beman-submodule update` to update the state of the beman submodule to the new +`.beman_submodule` settings. + +## How can I make CI ensure that my beman submodules are in a valid state? + +Add this job to your CI workflow: + +```yaml + beman-submodule-test: + runs-on: ubuntu-latest + name: "Check beman submodules for consistency" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: beman submodule consistency check + run: | + (set -o pipefail; ./infra/tools/beman-submodule/beman-submodule status | grep -qvF '+') +``` + +This will fail if the contents of any beman submodule don't match what's specified in the +`.beman_submodule` file. diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule new file mode 100755 index 00000000..2007fc49 --- /dev/null +++ b/tools/beman-submodule/beman-submodule @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import argparse +import configparser +import filecmp +import os +import pathlib +import shutil +import subprocess +import sys +import tempfile + +def directory_compare(dir1, dir2, ignore): + compared = filecmp.dircmp(dir1, dir2, ignore=ignore) + if compared.left_only or compared.right_only or compared.diff_files: + return False + for common_dir in compared.common_dirs: + path1 = os.path.join(dir1, common_dir) + path2 = os.path.join(dir2, common_dir) + if not directory_compare(path1, path2, ignore): + return False + return True + +class BemanSubmodule: + def __init__(self, dirpath, remote, commit_hash): + self.dirpath = dirpath + self.remote = remote + self.commit_hash = commit_hash + +def parse_beman_submodule_file(path): + config = configparser.ConfigParser() + read_result = config.read(path) + def fail(): + raise Exception(f'Failed to parse {path} as a .beman_submodule file') + if not read_result: + fail() + if not 'beman_submodule' in config: + fail() + if not 'remote' in config['beman_submodule']: + fail() + if not 'commit_hash' in config['beman_submodule']: + fail() + return BemanSubmodule( + str(pathlib.Path(path).resolve().parent), + config['beman_submodule']['remote'], config['beman_submodule']['commit_hash']) + +def get_beman_submodule(dir): + beman_submodule_filepath = os.path.join(dir, '.beman_submodule') + if os.path.isfile(beman_submodule_filepath): + return parse_beman_submodule_file(beman_submodule_filepath) + else: + return None + +def find_beman_submodules_in(dir): + assert os.path.isdir(dir) + result = [] + for dirpath, _, filenames in os.walk(dir): + if '.beman_submodule' in filenames: + result.append(parse_beman_submodule_file(os.path.join(dirpath, '.beman_submodule'))) + return sorted(result, key=lambda module: module.dirpath) + +def cwd_git_repository_path(): + process = subprocess.run( + ['git', 'rev-parse', '--show-toplevel'], capture_output=True, text=True, + check=False) + if process.returncode == 0: + return process.stdout.strip() + elif "fatal: not a git repository" in process.stderr: + return None + else: + raise Exception("git rev-parse --show-toplevel failed") + +def clone_beman_submodule_into_tmpdir(beman_submodule, remote): + tmpdir = tempfile.TemporaryDirectory() + subprocess.run( + ['git', 'clone', beman_submodule.remote, tmpdir.name], capture_output=True, + check=True) + if not remote: + subprocess.run( + ['git', '-C', tmpdir.name, 'reset', '--hard', beman_submodule.commit_hash], + capture_output=True, check=True) + return tmpdir + +def beman_submodule_status(beman_submodule): + tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, False) + if directory_compare(tmpdir.name, beman_submodule.dirpath, ['.beman_submodule', '.git']): + status_character=' ' + else: + status_character='+' + parent_repo_path = cwd_git_repository_path() + if not parent_repo_path: + raise Exception('this is not a git repository') + relpath = pathlib.Path( + beman_submodule.dirpath).relative_to(pathlib.Path(parent_repo_path)) + return status_character + ' ' + beman_submodule.commit_hash + ' ' + str(relpath) + +def beman_submodule_update(beman_submodule, remote): + tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, remote) + shutil.rmtree(beman_submodule.dirpath) + with open(os.path.join(tmpdir.name, '.beman_submodule'), 'w') as f: + f.write('[beman_submodule]\n') + f.write(f'remote={beman_submodule.remote}\n') + f.write(f'commit_hash={beman_submodule.commit_hash}\n') + shutil.rmtree(os.path.join(tmpdir.name, '.git')) + shutil.copytree(tmpdir.name, beman_submodule.dirpath) + +def update_command(remote, path): + if not path: + parent_repo_path = cwd_git_repository_path() + if not parent_repo_path: + raise Exception('this is not a git repository') + beman_submodules = find_beman_submodules_in(parent_repo_path) + else: + beman_submodule = get_beman_submodule(path) + if not beman_submodule: + raise Exception(f'{path} is not a beman_submodule') + beman_submodules = [beman_submodule] + for beman_submodule in beman_submodules: + beman_submodule_update(beman_submodule, remote) + +def add_command(repository, path): + tmpdir = tempfile.TemporaryDirectory() + subprocess.run( + ['git', 'clone', repository], capture_output=True, check=True, cwd=tmpdir.name) + repository_name = os.listdir(tmpdir.name)[0] + if not path: + path = repository_name + if os.path.exists(path): + raise Exception(f'{path} exists') + os.makedirs(path) + tmpdir_repo = os.path.join(tmpdir.name, repository_name) + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir_repo) + with open(os.path.join(tmpdir_repo, '.beman_submodule'), 'w') as f: + f.write('[beman_submodule]\n') + f.write(f'remote={repository}\n') + f.write(f'commit_hash={sha_process.stdout.strip()}\n') + shutil.rmtree(os.path.join(tmpdir_repo, '.git')) + shutil.copytree(tmpdir_repo, path, dirs_exist_ok=True) + +def status_command(paths): + if not paths: + parent_repo_path = cwd_git_repository_path() + if not parent_repo_path: + raise Exception('this is not a git repository') + beman_submodules = find_beman_submodules_in(parent_repo_path) + else: + beman_submodules = [] + for path in paths: + beman_submodule = get_beman_submodule(path) + if not beman_submodule: + raise Exception(f'{path} is not a beman_submodule') + beman_submodules.append(beman_submodule) + for beman_submodule in beman_submodules: + print(beman_submodule_status(beman_submodule)) + +def get_parser(): + parser = argparse.ArgumentParser(description='Beman pseudo-submodule tool') + subparsers = parser.add_subparsers(dest='command', help='available commands') + parser_update = subparsers.add_parser('update', help='update beman_submodules') + parser_update.add_argument( + '--remote', action='store_true', + help='update a beman_submodule to its latest from upstream') + parser_update.add_argument( + 'beman_submodule_path', nargs='?', + help='relative path to the beman_submodule to update') + parser_add = subparsers.add_parser('add', help='add a new beman_submodule') + parser_add.add_argument('repository', help='git repository to add') + parser_add.add_argument( + 'path', nargs='?', help='path where the repository will be added') + parser_status = subparsers.add_parser( + 'status', help='show the status of beman_submodules') + parser_status.add_argument('paths', nargs='*') + return parser + +def parse_args(args): + return get_parser().parse_args(args); + +def usage(): + return get_parser().format_help() + +def run_command(args): + if args.command == 'update': + update_command(args.remote, args.beman_submodule_path) + elif args.command == 'add': + add_command(args.repository, args.path) + elif args.command == 'status': + status_command(args.paths) + else: + raise Exception(usage()) + +def check_for_git(path): + env = os.environ.copy() + if path is not None: + env["PATH"] = path + return shutil.which("git", path=env.get("PATH")) is not None + +def main(): + try: + if not check_for_git(None): + raise Exception('git not found in PATH') + args = parse_args(sys.argv[1:]) + run_command(args) + except Exception as e: + print("Error:", e, file=sys.stderr) + sys.exit(1) + +if __name__ == '__main__': + main() diff --git a/tools/beman-submodule/test/test_beman_submodule.py b/tools/beman-submodule/test/test_beman_submodule.py new file mode 100644 index 00000000..47e2303c --- /dev/null +++ b/tools/beman-submodule/test/test_beman_submodule.py @@ -0,0 +1,359 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import os +import pathlib +import pytest +import shutil +import stat +import subprocess +import tempfile + +# https://stackoverflow.com/a/19011259 +import types +import importlib.machinery +loader = importlib.machinery.SourceFileLoader( + 'beman_submodule', + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../beman-submodule')) +beman_submodule = types.ModuleType(loader.name) +loader.exec_module(beman_submodule) + +def create_test_git_repository(): + tmpdir = tempfile.TemporaryDirectory() + subprocess.run(['git', 'init'], check=True, cwd=tmpdir.name, capture_output=True) + def make_commit(a_txt_contents): + with open(os.path.join(tmpdir.name, 'a.txt'), 'w') as f: + f.write(a_txt_contents) + subprocess.run( + ['git', 'add', 'a.txt'], check=True, cwd=tmpdir.name, capture_output=True) + subprocess.run( + ['git', '-c', 'user.name=test', '-c', 'user.email=test@example.com', 'commit', + '--author="test "', '-m', 'test'], + check=True, cwd=tmpdir.name, capture_output=True) + make_commit('A') + make_commit('a') + return tmpdir + +def test_directory_compare(): + def create_dir_structure(dir_path): + bar_path = os.path.join(dir_path, 'bar') + os.makedirs(bar_path) + + with open(os.path.join(dir_path, 'foo.txt'), 'w') as f: + f.write('foo') + with open(os.path.join(bar_path, 'baz.txt'), 'w') as f: + f.write('baz') + + with tempfile.TemporaryDirectory() as dir_a, \ + tempfile.TemporaryDirectory() as dir_b: + + create_dir_structure(dir_a) + create_dir_structure(dir_b) + + assert beman_submodule.directory_compare(dir_a, dir_b, []) + + with open(os.path.join(os.path.join(dir_a, 'bar'), 'quux.txt'), 'w') as f: + f.write('quux') + + assert not beman_submodule.directory_compare(dir_a, dir_b, []) + assert beman_submodule.directory_compare(dir_a, dir_b, ['quux.txt']) + +def test_parse_beman_submodule_file(): + def valid_file(): + tmpfile = tempfile.NamedTemporaryFile() + tmpfile.write('[beman_submodule]\n'.encode('utf-8')) + tmpfile.write( + 'remote=git@github.com:bemanproject/infra.git\n'.encode('utf-8')) + tmpfile.write( + 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8')) + tmpfile.flush() + module = beman_submodule.parse_beman_submodule_file(tmpfile.name) + assert module.dirpath == str(pathlib.Path(tmpfile.name).resolve().parent) + assert module.remote == 'git@github.com:bemanproject/infra.git' + assert module.commit_hash == '9b88395a86c4290794e503e94d8213b6c442ae77' + valid_file() + def invalid_file_missing_remote(): + threw = False + try: + tmpfile = tempfile.NamedTemporaryFile() + tmpfile.write('[beman_submodule]\n'.encode('utf-8')) + tmpfile.write( + 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8')) + tmpfile.flush() + beman_submodule.parse_beman_submodule_file(tmpfile.name) + except: + threw = True + assert threw + invalid_file_missing_remote() + def invalid_file_missing_commit_hash(): + threw = False + try: + tmpfile = tempfile.NamedTemporaryFile() + tmpfile.write('[beman_submodule]\n'.encode('utf-8')) + tmpfile.write( + 'remote=git@github.com:bemanproject/infra.git\n'.encode('utf-8')) + tmpfile.flush() + beman_submodule.parse_beman_submodule_file(tmpfile.name) + except: + threw = True + assert threw + invalid_file_missing_commit_hash() + def invalid_file_wrong_section(): + threw = False + try: + tmpfile = tempfile.NamedTemporaryFile() + tmpfile.write('[invalid]\n'.encode('utf-8')) + tmpfile.write( + 'remote=git@github.com:bemanproject/infra.git\n'.encode('utf-8')) + tmpfile.write( + 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8')) + tmpfile.flush() + beman_submodule.parse_beman_submodule_file(tmpfile.name) + except: + threw = True + assert threw + invalid_file_wrong_section() + +def test_get_beman_submodule(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + assert beman_submodule.get_beman_submodule('foo') + os.remove('foo/.beman_submodule') + assert not beman_submodule.get_beman_submodule('foo') + os.chdir(original_cwd) + +def test_find_beman_submodules_in(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + beman_submodules = beman_submodule.find_beman_submodules_in(tmpdir2.name) + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + sha = sha_process.stdout.strip() + assert beman_submodules[0].dirpath == os.path.join(tmpdir2.name, 'bar') + assert beman_submodules[0].remote == tmpdir.name + assert beman_submodules[0].commit_hash == sha + assert beman_submodules[1].dirpath == os.path.join(tmpdir2.name, 'foo') + assert beman_submodules[1].remote == tmpdir.name + assert beman_submodules[1].commit_hash == sha + os.chdir(original_cwd) + +def test_cwd_git_repository_path(): + original_cwd = os.getcwd() + tmpdir = tempfile.TemporaryDirectory() + os.chdir(tmpdir.name) + assert not beman_submodule.cwd_git_repository_path() + subprocess.run(['git', 'init']) + assert beman_submodule.cwd_git_repository_path() == tmpdir.name + os.chdir(original_cwd) + +def test_clone_beman_submodule_into_tmpdir(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + sha = sha_process.stdout.strip() + beman_submodule.add_command(tmpdir.name, 'foo') + module = beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo')) + module.commit_hash = sha + tmpdir3 = beman_submodule.clone_beman_submodule_into_tmpdir(module, False) + assert not beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git']) + tmpdir4 = beman_submodule.clone_beman_submodule_into_tmpdir(module, True) + assert beman_submodule.directory_compare(tmpdir.name, tmpdir4.name, ['.git']) + subprocess.run( + ['git', 'reset', '--hard', sha], capture_output=True, check=True, + cwd=tmpdir.name) + assert beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git']) + os.chdir(original_cwd) + +def test_beman_submodule_status(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + sha = sha_process.stdout.strip() + assert ' ' + sha + ' foo' == beman_submodule.beman_submodule_status( + beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo'))) + with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), 'a.txt'), 'w') as f: + f.write('b') + assert '+ ' + sha + ' foo' == beman_submodule.beman_submodule_status( + beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo'))) + os.chdir(original_cwd) + +def test_update_command_no_paths(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + sha = sha_process.stdout.strip() + subprocess.run( + ['git', 'reset', '--hard', sha], capture_output=True, check=True, + cwd=tmpdir.name) + with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'w') as f: + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') + with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), '.beman_submodule'), 'w') as f: + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') + beman_submodule.update_command(tmpdir.name, None) + assert beman_submodule.directory_compare( + tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule']) + assert beman_submodule.directory_compare( + tmpdir.name, os.path.join(tmpdir2.name, 'bar'), ['.git', '.beman_submodule']) + os.chdir(original_cwd) + +def test_update_command_with_path(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + tmpdir_copy1 = tempfile.TemporaryDirectory() + shutil.copytree(tmpdir.name, tmpdir_copy1.name, dirs_exist_ok=True) + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + sha = sha_process.stdout.strip() + subprocess.run( + ['git', 'reset', '--hard', sha], capture_output=True, check=True, + cwd=tmpdir.name) + with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'w') as f: + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') + with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), '.beman_submodule'), 'w') as f: + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') + beman_submodule.update_command(tmpdir.name, 'foo') + assert beman_submodule.directory_compare( + tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule']) + assert beman_submodule.directory_compare( + tmpdir_copy1.name, os.path.join(tmpdir2.name, 'bar'), ['.git', '.beman_submodule']) + os.chdir(original_cwd) + +def test_add_command(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + sha = sha_process.stdout.strip() + assert beman_submodule.directory_compare( + tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule']) + with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n' + os.chdir(original_cwd) + +def test_status_command_no_paths(capsys): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), 'a.txt'), 'w') as f: + f.write('b') + beman_submodule.status_command([]) + sha = sha_process.stdout.strip() + assert capsys.readouterr().out == '+ ' + sha + ' bar\n' + ' ' + sha + ' foo\n' + os.chdir(original_cwd) + +def test_status_command_with_path(capsys): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = os.getcwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), 'a.txt'), 'w') as f: + f.write('b') + beman_submodule.status_command(['bar']) + sha = sha_process.stdout.strip() + assert capsys.readouterr().out == '+ ' + sha + ' bar\n' + os.chdir(original_cwd) + +def test_check_for_git(): + tmpdir = tempfile.TemporaryDirectory() + assert not beman_submodule.check_for_git(tmpdir.name) + fake_git_path = os.path.join(tmpdir.name, 'git') + with open(fake_git_path, 'w'): + pass + os.chmod(fake_git_path, stat.S_IRWXU) + assert beman_submodule.check_for_git(tmpdir.name) + +def test_parse_args(): + def plain_update(): + args = beman_submodule.parse_args(['update']) + assert args.command == 'update' + assert not args.remote + assert not args.beman_submodule_path + plain_update() + def update_remote(): + args = beman_submodule.parse_args(['update', '--remote']) + assert args.command == 'update' + assert args.remote + assert not args.beman_submodule_path + update_remote() + def update_path(): + args = beman_submodule.parse_args(['update', 'infra/']) + assert args.command == 'update' + assert not args.remote + assert args.beman_submodule_path == 'infra/' + update_path() + def update_path_remote(): + args = beman_submodule.parse_args(['update', '--remote', 'infra/']) + assert args.command == 'update' + assert args.remote + assert args.beman_submodule_path == 'infra/' + update_path_remote() + def plain_add(): + args = beman_submodule.parse_args(['add', 'git@github.com:bemanproject/infra.git']) + assert args.command == 'add' + assert args.repository == 'git@github.com:bemanproject/infra.git' + assert not args.path + plain_add() + def add_path(): + args = beman_submodule.parse_args( + ['add', 'git@github.com:bemanproject/infra.git', 'infra/']) + assert args.command == 'add' + assert args.repository == 'git@github.com:bemanproject/infra.git' + assert args.path == 'infra/' + add_path() + def plain_status(): + args = beman_submodule.parse_args(['status']) + assert args.command == 'status' + assert args.paths == [] + plain_status() + def status_one_module(): + args = beman_submodule.parse_args(['status', 'infra/']) + assert args.command == 'status' + assert args.paths == ['infra/'] + status_one_module() + def status_multiple_modules(): + args = beman_submodule.parse_args(['status', 'infra/', 'foobar/']) + assert args.command == 'status' + assert args.paths == ['infra/', 'foobar/'] + status_multiple_modules() From 1fe6d19f4b3d3b0efa1754423e401682c90934d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 11 Jun 2025 23:28:51 +0300 Subject: [PATCH 166/371] beman-tidy: improve docs --- tools/beman-tidy/.beman-standard.yml | 2 +- tools/beman-tidy/README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/.beman-standard.yml index 0feee03c..a6095830 100644 --- a/tools/beman-tidy/.beman-standard.yml +++ b/tools/beman-tidy/.beman-standard.yml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# TODO: 07.06.2025: This file is a partial stable snapshot of the standard. +# 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. # LICENSE diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 86e3b668..4fb6b635 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -9,7 +9,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception `beman-tidy` is a tool used to check and apply [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: `07.06.2025`: In order to make the best and quickly use of the tool in the entire organization, most of the checks will not support the `--fix-inplace` flag in the first iteration. +Note: `2025-06-07`: In order to make the best and quickly use of the tool in the entire organization, most of the checks will not support the `--fix-inplace` flag in the first iteration. ## Installation @@ -110,14 +110,14 @@ Expected Development Flow: Requirements: * `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. -* `beman-tidy` must NOT used internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). +* `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). * `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. Limitations: -* `07.06.2025`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. -* `07.06.2025`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard is not stable. Thus, the tool itself may be unstable. +* `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. +* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard is not stable. Thus, the tool itself may be unstable. ### Tree structure From 0297096d6a35bfdba80cf41d87fea8a1ff1e55bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 11 Jun 2025 23:54:37 +0300 Subject: [PATCH 167/371] beman-tidy: improve docs - extract parts from README into docs/dev-guide.md --- tools/beman-tidy/README.md | 154 +--------------------------- tools/beman-tidy/docs/dev-guide.md | 155 +++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 153 deletions(-) create mode 100644 tools/beman-tidy/docs/dev-guide.md diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 4fb6b635..9c0b8bb6 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -99,156 +99,4 @@ $ ./beman-tidy ../exemplar --fix-inplace --verbose ## beman-tidy Development -Expected Development Flow: - -* Find a Beman Standard check that is not implemented. -* Add a new entry to the `.beman-standard.yml` file. -* Add a new check to the `lib/checks/beman_standard/` directory (find existing checks for inspiration). -* Add tests for the new check. -* Run the tests. -* Commit the changes. - -Requirements: -* `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. -* `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). -* `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. - -Limitations: -* `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. -* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard is not stable. Thus, the tool itself may be unstable. - -### Tree structure - -```shell - $ tree . -. -├── beman-tidy # The beman-tidy tool entry point (Python script). -├── .beman-standard.yml # The Beman Standard configuration file. -├── __init__.py # Allows recursive Python packages imports. -├── README.md # Root README / docs. -├── Makefile # Makefile for the beman-tidy tool. -├── requirements.txt # Production requirements. -├── requirements-dev.txt # Development requirements. -├── lib # The library for the beman-tidy tool (e.g, checks, utils, etc.). -│   ├── __init__.py # Recursive Python packages imports -│   ├── checks # The checks for the beman-tidy tool. -│   │   ├── __init__.py -│   │   ├── base # Base classes for the checks - not to be used directly. -│   │   │   ├── __init__.py -│   │   │   ├── base_check.py # Base class for all checks. -│   │   │   ├── directory_base_check.py # Base class for directory checks. -│   │   │   └── file_base_check.py # Base class for file checks. -│   │   ├── beman_standard # The ACTUAL checks for the beman standard. -│   │   │   ├── __init__.py -│   │   │   ├── cmake.py # CMake related checks. -│   │   │   ├── cpp.py # C++ related checks. -│   │   │   ├── directory.py # Directory related checks. -│   │   │   ├── file.py # File related checks. -│   │   │   ├── general.py # General checks. -│   │   │   ├── license.py # License related checks. -│   │   │   ├── readme.py # README.md related checks. -│   │   │   ├── release.py # Release related checks. -│   │   │   └── toplevel.py # Top-level checks. -│   │   └── system # System related checks. -│   │   ├── __init__.py -│   │   ├── git.py # Git related checks (internal use only). -│   │   └── registry.py # Registry related checks (internal use only). -│   ├── pipeline.py # The pipeline for the beman-tidy tool. -│   └── utils # Utility functions for the beman-tidy tool. -│   ├── __init__.py -│   ├── git.py -│   ├── string.py -│   └── terminal.py -└── tests # The tests for the beman-tidy tool. - ├── __init__.py - ├── beman_standard - │   ├── __init__.py - │   └── readme # The tests for the README.md check. - │   ├── __init__.py - │   ├── conftest.py # The conftest for the pytest tests. - │   ├── data # The data for the tests (e.g., file, directory, etc.). - │   │   ├── invalid - │   │   │   ├── README.md - │   │   │   └── README.md.delete_me - │   │   └── valid - │   │   └── README.md - │   └── test_readme.py - ├── conftest.py - └── utils - ├── __init__.py - └── conftest.py - -24 directories, 62 files -``` - -Notes: - -* `beman-tidy`: A Python script that is used to check and apply the Beman Standard to a repository. -* `.beman-standard.yml`: Stable version of the standard; the tool does not fetch the latest unstable version of the standard. -* `lib/`: The library for the beman-tidy tool (e.g, checks, utils, etc.). - * `lib/checks/beman_standard/`: Direct implementation of the checks from the standard (e.g, `lib/checks/beman_standard/readme.py` is the implementation of the `README.md` checks). - * `lib/checks/base/`: Base classes for the checks - not to be used directly. - * `lib/pipeline.py`: The pipeline for the `beman-tidy` tool. -* `tests/`: The tests for the beman-tidy tool. - * Structure is similar to the `lib/` directory. - * `pytest` is used for testing. - -### Linting - -Run the linter: - -```shell -# Run the linter - dry run. -$ make lint -# Run the linter - fix issues. -$ make lint-fix -``` - -### Testing - -#### Running Tests - -Run the tests: - -```shell -$ make install-dev -pip3 install -r requirements-dev.txt -...q -$ make test -Running tests... -python3 -m pytest tests/ -v -========================================================================================================= test session starts ========================================================================================================= -platform darwin -- Python 3.9.6, pytest-8.4.0, pluggy-1.6.0 -- /Library/Developer/CommandLineTools/usr/bin/python3 -cachedir: .pytest_cache -rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy -collected 3 items - -tests/beman_standard/readme/test_readme.py::test__README_TITLE__valid PASSED [ 33%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__invalid PASSED [ 66%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__fix_invalid PASSED [100%] - -========================================================================================================== 3 passed in 0.08s ========================================================================================================== - - -``` - -#### Writing Tests - -* `tests/beman_standard//test_.py`: The test file for the `` check. - * e.g., for `check_category = "readme"` the test file is `tests/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()`. -* `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/beman_standard/readme/data/valid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in `tests/beman_standard/readme/data/invalid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "fix_invalid"` the data may use both `valid` and `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` (which are not tracked by git). -* Default setup / mocks: - * `repo_info`: The repository information (e.g., path, name, etc.). Mocked with hardcoded values of `beman.exemplar`. - * `beman_standard_check_config`: The Beman Standard configuration file. Actual load of the `.beman-standard.yml` file. -* Always add at least 3 test cases for each check. - * `valid`: The test case for the valid case. - * `invalid`: The test case for the invalid case. - * `fix_invalid`: 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. +Please refer to the [Beman Tidy Development Guide](./docs/dev-guide.md) for more details. \ No newline at end of file diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md new file mode 100644 index 00000000..6405e3db --- /dev/null +++ b/tools/beman-tidy/docs/dev-guide.md @@ -0,0 +1,155 @@ +# Beman Tidy Development Guide + +Expected Development Flow: + +* Find a Beman Standard check that is not implemented. +* Add a new entry to the `.beman-standard.yml` file. +* Add a new check to the `lib/checks/beman_standard/` directory (find existing checks for inspiration). +* Add tests for the new check. +* Run the tests. +* Commit the changes. + +Requirements: +* `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. +* `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). +* `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. + +Limitations: +* `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. +* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard is not stable. Thus, the tool itself may be unstable. + +## Tree structure + +```shell + $ tree . +. +├── beman-tidy # The beman-tidy tool entry point (Python script). +├── .beman-standard.yml # The Beman Standard configuration file. +├── __init__.py # Allows recursive Python packages imports. +├── README.md # Root README / docs. +├── Makefile # Makefile for the beman-tidy tool. +├── requirements.txt # Production requirements. +├── requirements-dev.txt # Development requirements. +├── lib # The library for the beman-tidy tool (e.g, checks, utils, etc.). +│   ├── __init__.py # Recursive Python packages imports +│   ├── checks # The checks for the beman-tidy tool. +│   │   ├── __init__.py +│   │   ├── base # Base classes for the checks - not to be used directly. +│   │   │   ├── __init__.py +│   │   │   ├── base_check.py # Base class for all checks. +│   │   │   ├── directory_base_check.py # Base class for directory checks. +│   │   │   └── file_base_check.py # Base class for file checks. +│   │   ├── beman_standard # The ACTUAL checks for the beman standard. +│   │   │   ├── __init__.py +│   │   │   ├── cmake.py # CMake related checks. +│   │   │   ├── cpp.py # C++ related checks. +│   │   │   ├── directory.py # Directory related checks. +│   │   │   ├── file.py # File related checks. +│   │   │   ├── general.py # General checks. +│   │   │   ├── license.py # License related checks. +│   │   │   ├── readme.py # README.md related checks. +│   │   │   ├── release.py # Release related checks. +│   │   │   └── toplevel.py # Top-level checks. +│   │   └── system # System related checks. +│   │   ├── __init__.py +│   │   ├── git.py # Git related checks (internal use only). +│   │   └── registry.py # Registry related checks (internal use only). +│   ├── pipeline.py # The pipeline for the beman-tidy tool. +│   └── utils # Utility functions for the beman-tidy tool. +│   ├── __init__.py +│   ├── git.py +│   ├── string.py +│   └── terminal.py +└── tests # The tests for the beman-tidy tool. + ├── __init__.py + ├── beman_standard + │   ├── __init__.py + │   └── readme # The tests for the README.md check. + │   ├── __init__.py + │   ├── conftest.py # The conftest for the pytest tests. + │   ├── data # The data for the tests (e.g., file, directory, etc.). + │   │   ├── invalid + │   │   │   ├── README.md + │   │   │   └── README.md.delete_me + │   │   └── valid + │   │   └── README.md + │   └── test_readme.py + ├── conftest.py + └── utils + ├── __init__.py + └── conftest.py + +24 directories, 62 files +``` + +Notes: + +* `beman-tidy`: A Python script that is used to check and apply the Beman Standard to a repository. +* `.beman-standard.yml`: Stable version of the standard; the tool does not fetch the latest unstable version of the standard. +* `lib/`: The library for the beman-tidy tool (e.g, checks, utils, etc.). + * `lib/checks/beman_standard/`: Direct implementation of the checks from the standard (e.g, `lib/checks/beman_standard/readme.py` is the implementation of the `README.md` checks). + * `lib/checks/base/`: Base classes for the checks - not to be used directly. + * `lib/pipeline.py`: The pipeline for the `beman-tidy` tool. +* `tests/`: The tests for the beman-tidy tool. + * Structure is similar to the `lib/` directory. + * `pytest` is used for testing. + +## Linting + +Run the linter: + +```shell +# Run the linter - dry run. +$ make lint +# Run the linter - fix issues. +$ make lint-fix +``` + +## Testing + +### Running Tests + +Run the tests: + +```shell +$ make install-dev +pip3 install -r requirements-dev.txt +...q +$ make test +Running tests... +python3 -m pytest tests/ -v +========================================================================================================= test session starts ========================================================================================================= +platform darwin -- Python 3.9.6, pytest-8.4.0, pluggy-1.6.0 -- /Library/Developer/CommandLineTools/usr/bin/python3 +cachedir: .pytest_cache +rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy +collected 3 items + +tests/beman_standard/readme/test_readme.py::test__README_TITLE__valid PASSED [ 33%] +tests/beman_standard/readme/test_readme.py::test__README_TITLE__invalid PASSED [ 66%] +tests/beman_standard/readme/test_readme.py::test__README_TITLE__fix_invalid PASSED [100%] + +========================================================================================================== 3 passed in 0.08s ========================================================================================================== + + +``` + +### Writing Tests + +* `tests/beman_standard//test_.py`: The test file for the `` check. + * e.g., for `check_category = "readme"` the test file is `tests/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()`. +* `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/beman_standard/readme/data/valid/`. + * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in `tests/beman_standard/readme/data/invalid/`. + * e.g., for `check_category = "readme"` and `test_case_name = "fix_invalid"` the data may use both `valid` and `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` (which are not tracked by git). +* Default setup / mocks: + * `repo_info`: The repository information (e.g., path, name, etc.). Mocked with hardcoded values of `beman.exemplar`. + * `beman_standard_check_config`: The Beman Standard configuration file. Actual load of the `.beman-standard.yml` file. +* Always add at least 3 test cases for each check. + * `valid`: The test case for the valid case. + * `invalid`: The test case for the invalid case. + * `fix_invalid`: 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. From 4f5263a294120fcb497d2753d8fa7f7ed6e9b18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 12 Jun 2025 00:05:23 +0300 Subject: [PATCH 168/371] beman-tidy: rename default_check() to pre_check() --- tools/beman-tidy/lib/checks/base/base_check.py | 5 +++-- .../beman-tidy/lib/checks/base/directory_base_check.py | 5 ++--- tools/beman-tidy/lib/checks/base/file_base_check.py | 6 +++--- tools/beman-tidy/lib/pipeline.py | 2 +- tools/beman-tidy/tests/utils/file_testcase_runners.py | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 0ab8140b..6bc5c50b 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -54,9 +54,10 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): assert len(beman_library_maturity_model["values"]) == 4 self.beman_library_maturity_model = beman_library_maturity_model["values"] - def default_check(self): + def pre_check(self): """ - Checks if this rule is properly initialized. + Pre-checks if this rule is properly initialized. + Usually, this is internal use only. """ if self.name is None: self.log("The name is not set.") diff --git a/tools/beman-tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/lib/checks/base/directory_base_check.py index a37baa84..3b16f443 100644 --- a/tools/beman-tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/lib/checks/base/directory_base_check.py @@ -18,12 +18,11 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): # set path - e.g. "src/beman/exemplar" self.path = os.path.join(repo_info["top_level"], relative_path) - def default_check(self): + def pre_check(self): """ Override. - Checks if this rule is properly initialized. """ - if not super().default_check(): + if not super().pre_check(): return False # TODO: Implement the default check. diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index be5a0ac5..879b68f0 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -19,12 +19,12 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): # set path - e.g. "README.md" self.path = os.path.join(repo_info["top_level"], relative_path) - def default_check(self): + def pre_check(self): """ Override. - Checks if this rule is properly initialized. + Pre-checks if the file exists and is not empty. """ - if not super().default_check(): + if not super().pre_check(): return False if self.path is None: diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 9406f0af..073766dc 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -52,7 +52,7 @@ def run_check(check_class, log_enabled=args.verbose): log( f"Running check [{check_instance.type}][{check_instance.name}] ... ") - if (check_instance.default_check() and check_instance.check()) or (args.fix_inplace and check_instance.fix()): + 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") return True else: diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index 828eb081..ae22b30f 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -9,10 +9,10 @@ def file_testcase_run(file_path, check_class, repo_info, beman_standard_check_co check_instance.path = file_path check_instance.log_level = True - assert check_instance.default_check( - ) is True, f"Default check failed for {file_path}" + assert check_instance.pre_check( + ) is True, f"[{check_instance.__name__}] pre_check() failed for {file_path}" assert check_instance.check( - ) is expected_result, f"Check failed for {file_path}" + ) is expected_result, f"[{check_instance.__name__}] check() failed for {file_path}" def file_testcase_run_valid(file_path, check_class, repo_info, beman_standard_check_config): @@ -30,12 +30,12 @@ def file_testcase_run_fix_invalid(invalid_file_path, check_class, repo_info, bem check_instance.path = f"{invalid_file_path}.delete_me" check_instance.write(invalid_file_path.read_text()) - assert check_instance.default_check() is True + assert check_instance.pre_check() is True assert check_instance.check() is False assert check_instance.fix() is True - assert check_instance.default_check() is True + assert check_instance.pre_check() is True assert check_instance.check() is True # Delete the temporary file From fa33763160766a0bc2c521c235f4c5e3852b53fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 12 Jun 2025 00:15:13 +0300 Subject: [PATCH 169/371] beman-tidy: update the coverage formula --- tools/beman-tidy/README.md | 38 ++++++++++------------ tools/beman-tidy/images/usage-example.png | Bin 63057 -> 0 bytes tools/beman-tidy/lib/pipeline.py | 29 ++++++----------- 3 files changed, 28 insertions(+), 39 deletions(-) delete mode 100644 tools/beman-tidy/images/usage-example.png diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 9c0b8bb6..461ab429 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -21,8 +21,6 @@ $ pip3 install -r requirements.txt ## Usage -![beman-tidy usage example](./images/usage-example.png) - * Display help: ```shell $ ./beman-tidy --help @@ -43,52 +41,52 @@ optional arguments: * Run beman-tidy on the exemplar repository (default: dry-run mode) ```shell -# non-verbose mode $ ./beman-tidy ../../../exemplar -Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). +# non-verbose mode +Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). -Coverage: 6.98% (3/43 checks passed). +Coverage: 66.67% (2/3 checks passed). # verbose mode - no errors $ ./beman-tidy ../../../exemplar --verbose beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED +Running check [RECOMMENDATION][README.TITLE] ... +[WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. + check [RECOMMENDATION][README.TITLE] ... FAILED -Running check [RECOMMENDATION][README.BADGES] ... +Running check [RECOMMENDATION][README.BADGES] ... check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED beman-tidy pipeline finished. -Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). +Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). -Coverage: 6.98% (3/43 checks passed). +Coverage: 66.67% (2/3 checks passed). # verbose mode - with errors -$ ./beman-tidy ../../../exemplar --verbose +$ ./beman-tidy ../../../exemplar --verbose beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... -[WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. - check [RECOMMENDATION][README.TITLE] ... FAILED +Running check [RECOMMENDATION][README.TITLE] ... + check [RECOMMENDATION][README.TITLE] ... PASSED -Running check [RECOMMENDATION][README.BADGES] ... +Running check [RECOMMENDATION][README.BADGES] ... check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED beman-tidy pipeline finished. -Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). +Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). -Coverage: 4.65% (2/43 checks passed). +Coverage: 100.0% (3/3 checks passed). ``` * Run beman-tidy on the exemplar repository (fix issues in-place): @@ -99,4 +97,4 @@ $ ./beman-tidy ../exemplar --fix-inplace --verbose ## beman-tidy Development -Please refer to the [Beman Tidy Development Guide](./docs/dev-guide.md) for more details. \ No newline at end of file +Please refer to the [Beman Tidy Development Guide](./docs/dev-guide.md) for more details. diff --git a/tools/beman-tidy/images/usage-example.png b/tools/beman-tidy/images/usage-example.png deleted file mode 100644 index 957fe8fe67c47ec8a7fa2d4b55e547aa633e930f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63057 zcmZU)19)Z4vOgT#oY=;WGqKG{GO@8^+t$R^#I`XpC)UKaCbpArzvtY0|L41RJ?)cH;LWDk!w*gX$->DZ z5hchHyBwYci4jk|2TofDlv8%-Dm&nwJe!T?SU&9Do75r$$D1}}qP%7cv#?QA=FXZzyZQ6S%@CO2ewljAUa{D!fv;T9Po6ZNrH8@qa3*T z;i7hMuP71nij-w(iIRDKgc;`rDYKS&B%?LMe-EIS_@0md?YxY6o+2vJ4?g=@0gSU)wdIv*NYzZK1exn(?e;yr`JcK6AC{~%RJXo&~PIu|(?F%;<( z!4?^eqM0I@9!o>9$0czmKPDcH9F3AB^iT@PihR4HMMB7GNO4Mb3S}z^_|BqYNKZ+JMNg=4{5@Sc zS)=KDwDN>Xl`?-Rt-2^39zAP{O0pY0Cj&B_ugaoY34?P=D+4z@Dy>p^S!G+L!*>L= zOf{JAg5@gTyVR1tyH~bU2&#!yW>he#>QuTZpZ{2ubA@&_cWvanf!&5a^$zE+;L{O7exmNV599Jea7q!GNdpe&rv$Tjhzm>O@=RX}_D9kR+ zv1~qL#$sk+`o*$svTorjBjE@79PL_J-*F)8%JQT~jAP2REoK$`B<0F}fJ`o(jg@(( zg|?B`91>R}_g)4O%c((#)_z+=Pnp$h9na`byBy0+LqX$wQ*^@w>shO7tNM@K^q~%1 zccu?3OY;n4&-t6~l+Kjg?={~$76`0Wty^3}?`;VhVp-)+f~8*XL@9RM9V*60+B@*#%7+UYhi5w>isx-P6UjV|}#jl=E?XYlKP*5rE%| zw2Lf`1b8Cp^IW%G-}C3qz^IjcDFwTTsq%Hj>{CtVT4`H10P%X$hRlFWDMAa;)*a zmfj!VpWSB@xNzC5urwreUtdvMsIHex5qACT{8>LKm}T9H)=Fvr%(=wY`t@;Raisd( zGt)EcRc1TiD-GO%yb=iHMt`|b(eC2k}Day9tH*=`C;W%&+L7Z=>F)QG#|Gtj1vFQK% zQr^77`Srwr(XX7R(z#{#=kBlUqsXJ%DgTamU!w-Gnd=+l{-N2ah3rRwgkHO^=gPq* z!-qzV-hH=MdDN!sPUd)X<5G4_?k|y!*;U)EjXx$!&Mz7r21<{sk1gviZ7YjM%S)R* zMW1g0YrR7{IjuFDz|9L{UEXCOEI}7@kDz}?P12vzRi)D$Eg?R>3xUl?pXb|p z+#uXJ!0l)JYvE1Gb)~9*`{xQfIw$Lc_S4H+RzYipz4hiw_vufh9G^SE`}aGwKG+4+ zW)e%14nYY&FW#;P_6z3~+$6xc!F!M3Q|ilkRsfahq%1fV+qQ=|cV{_x03kA1F)G;Z z4Ue9H^~`!}FJs{6p!2Ht;u*Mw_9!NSTG6XMb>5dKkbLiIwl59jv;UrVLO)0gN7$ zh64i+w*-R%rNBWqKIjGmgG>wqg9SY?K(}}v#D7yEZu21jI}Oh9PeBn?F&P=qQ`N-D z%*@W&!rrCywR;OBYSB_n(?wH3p4Y_Qmf6VE-q?)U!`9&+7BGGfUQp83%*BY*!`8;m znb$*r{9h$_LFs?80pz6rD&k@-K(48vOe$vYWJb!x%)-nKqZ)*J?&hKJecg9DgG_wzvYOV zIh#0HI=EQc+mZew*T~r3)kT1u{GW>c=lXX$%{(msUrlz-|J5x}2Lb<30IbX`fd7#V zV&(rQmsi=+!^}oY+|m{_JfJ!R*;&5w|Ev7}q5QuZ|ASNW|8a72a{edhe^CB6=XYl_ zCoy|lP?au%|8Hjgi}^o^|Ha4;_^0RpF%thC=6~ga##s=7AMihOCWw#~K}!V&CJZJc zE~4fEex?WOfi1BlcmiKU(-eY%Azl%1N3RfXe4r7iG{jsM5u_ZtDsexGGi#v0&~sOjN_X6s!$Glzm{PTf$OjH{=AlX5MQpOpk(za zt%qJy7QpH~8I&;)K}h=bYx?0thS=klzmS<3kK#C94%RP&PI; z`hJz6E-*MvtJ38998%QU7TdKy47HsqbfYwslxQ%hCnqN<{g5wfOQ$#{W>|A%kXlb zsvl9eEmuEvn|}x#9ueZ0NGV&aTlIN?f>BwU-5Xu&xpAnYb^*7WxN<2`P+M&69bXFG zs>OG?>QLjo6RT)0LepG}DIf6g(%h)HQ8V~{V2!VV()j%e4!NTYP|{U`;pM+EaG8mR(LpU3=v;y zVp5WX4_s?)*8{$Uq-6WhrLmM3NGr?jx4PR$dFR44N+$BM;Ax1?Py0qKO8P1gmF7g- zwoeWYB)B(RFp)_Fb(?l1WAJ~W=|FdB!Y#wydPNrOsD}gv1=$pc#rJ%?oLZhPR&!lU z@q2iC6TpZCSK1)hVafF&6U>cr`nL_P>P@UG#L531A?sZ@GMahcjztsypHy0X83KM+Zf^!4D@a>rcV4ZT0W zyo*`jWPNe6>ERbVf8jObL22m;aAthkU}s!@NE`u=F z!NBO7@|aq8`w`V$##*n0nDzAtld#eOE~Df)gtpSN=^ZUr-|A*Ooq>Y!>9)>H*7`?h z3Y3t)c@_rVin}~Czv5duJyUxC(Cr^Jyv8NuX8z2@L~i;P-j6syp2;lk((|>}xxq-xljV97EL>cv zC>$mXBmbuz*!IIrYg%63Ok&S{^q1$OT+5Ai*TwQo9lKwlC?tZ6{ah9^0o|_`eE2Me zV8um6%B^-A$Hi&-gTax|Ez*b8;{_ec_3J0}IgLbTccUPX9euplV&gVW zRnaNYA)M!1M>ut&fpq#z)i6qT!k;*j9YxRftF+I%KfxqW1wmEvzs)E({|afs&`?b5 zhM^SF;>24oMjf)*gyKPn29{5j7_{XS*~t{bJ{90eL4f6Z_mVDA`9=Pe{$2_-pOPc zK0GJqRA1tYHLtl9t>4m-1L$7e5Nkibca8guR#NcCtU~P)_#*aawdA#!5br&{8qtqU z7jDC_&L>PRsterLS#+@3y4O@+)=0RnE)=cLi>_W9k!Lw;b(7@R`?;*d?7W?qlgX<- z_-0RR_D*?#Gf3RGhs3*Rba^oxUd5}+?>R^8c0#9+w%+UJp47c`VM=~4hU zO&iRIML;0u=jYdd2K~N14(O4;zP`4D@Af*`@_RjRvRa_$_5AZ7kilt<(`-2>X>m4N zDx*3#mCc8!;5VHkAmJbNVGpv_esNe|GY^liw##)QaLXAP8BpwTgM;F;QvKqK-2k^% zd+`@`^Qj_U*S`@>EIN++Bk1@%PL$6tFZd5Ty}i;v;VmQ|SQJ9(^78V2Q``~-7Cv6@ zhbm&9ltZ8zDz?nF@ioYzEjr>G^?mQZJNoWM(m=KJw$|0fNALEnkC!p!+xfqo&=_$# z9;9d>u;bglatw?Ud7?RG6^u#rs>TsPJssux=PcIfF+d#wCo@-|2n4)1Y}Z;8Iy;-K z7BEDGAP5D#lI_}dV6H_5v8V;r(reZ_J=qVAj^?UcH)S1$)e42yaOFhBAV@&h4%Dlt zyqs+R@ZYEFJ(v3hjk&&HSj*#?{C>picnzOpVxKFK{yUNqE}{fj#LDww0fqOikC03h z0y=qcUWK3iK~`m)74E{wK}6Tr*yGi9GZiiE&K&L>l@_-Xeg^THi~{%4A&a&&4E0yGH_loo`QR zGFqK;`M3g4&?sbsQ~D?kFSQi7%FDmsK>db~+OR0^r#2C!>o`4t;|BC&6A8ASBM4JP zSbD83lv26b%vS4|OyMHCzoCP~YV3M@!ObnW4M&;5eoXDklDr%Xt#Z$xIbXn1La~^q zp6G@y4}VNbtIfUljoW<`xSbzGK)e}omqCa5QQC%lFpK?|l9A6rf=36nCq(me+aC4W zokOtLE(or_J*}q{tqDEPDA$np)g7lg$48}YSeJ-=*R!tooaAtF z3l~5voLj(1{ACcC=~eKDFz;s`kpcHXa$TsOfNP?p*V>B60KaQ~5VEjhHHj6(e?J55IRO{B zo`-k|sahm<)a-emQaq%c!K4&U#r@{C4t<_lHd zm|M%@to`jb5`||*lYfcJ^|Ija1m5$EcUNJU>LVhQ&SqHT1kYYEEA_9?F0!F6kaUP#D z_#x=1CJ?YJa*Dmh+5P)>7sTXLK|a;+R_QId&=u_TlWPXn0;e+6FsGku#-aX=!@-Yk z1X;3QI5wM|o=v8siL$d3Vo@=I_EZdwXYi}@ptVi`&Oq6U({4Q-pUZ}p;}osTum?2| z!M9G$&UUp)=C1H*(J&yuPc0J??|z6)ud5qf+aHPg%zuO%2iznt7&?{~@**LJvQThc z9tZ}Qm>B59DIp1lMQxedmg~mdwNgjDC~>d%;03K>t!SxR9(%}vRQpWvg&sg#`0GAg zZRd%pkq3Bpb~dZv*nJW9oUv(FD4U-3;%inXDG6a^SdlDJc#;IO@l<$r-1NpKyA5rx z72VIbTcs>>bK-qidd3MiaN?%dFM<7Uz~9k$##WB&ZI0@xUk-wQE>swnqNleB(}u!J zN$-toj;xv;glC1l*W{b@e3jP%z31k&iEs1)0w?aK&+ZWR za9Qs_|9(**``A}cQ4azmAbLcg1KwB!7_v$n?p9t?VK|-9D^AN!E#S%G^Vg3kuA12{ zJf*^~e*_$lxI7tZrjq-Rln8*usA#JaulrmG{b%u^{2{{j`x^KoR}H60JjTkQfrg-+ z=uBiv&+KOHq1Hgw0cNHr8kBB)IBbttvF(NN!mA(g74eHvg0#VF?Mw`jch$8*4>aY( zQhU!;yQW(7N?oH4mu8{*K1>i(SyA0xcJHa~3&H>vwNRI|#qsoe5>tPq|KifH7sXGq z&c~nXxl<&QdylkPTZK1V7fuOQ-}JTCeHph&-UOSY{ZI7rspWZ;U{Q$qNlSMzcwi1& zbll>~uKClCuZS0E^Xa0?WMIAIlv zIB)aa(T74?xd_BWKBm#ip@pX&c3ZUijRe>j)$f8{aLcl8#bkz}!LmWNyigX){W28> zJ%XWOVF<7E%j0`mauMOsI2N=lX|otD-~(!?(%z`Z!ghAd8*Xd1^Z8=1tj#og`Hsfu z=z?IHc_FAwXW$H?Dji6~Gt6SAI)jbyiH5fb3V`(Yb*zd)e(5!BpXl{^298E6V58Z0lm>;B=t>qHkmS~g=N`)M zVY;azl8i1J^>vt?=k9c@vPx`$D}nwVlna*&xj(dYvK?>QKn}6)D}#Ih1o>%1pZe~U zzowXF23`Yd>Ejt~u9qYIz@%T6tdyBUvQn3qG@qNeDJQU3Ise^`|4LhSy*>uI5MuEV z|CNW{V2u@Xkksht?Qswv<9vJco8X>@ISJDCZrJ8v2|A6(1H*m6QisRZvoB-a>nJ$P zSZ#PI9y4$YVsKyrPTqQTT}ZL>a`iF_&p^u0QEVXOS&ne6-+b^$b@Q2=tk?YK1Vt{G zQV#gYwiC{6>u`Yt_ukPkkOREg=Se_z&n{s6FX~Jz+@+P z*4?)MJwRV#QnYn3Zo)$-&$!e$Y6Ph}R>PkLnV4FD4d)R$i-Ml%`)zEmaeMIcpz z>x}lm>wZ2YFhT^plRB8pqLi4|A>&>Y*P-?i_Y2|l1znL1xf#yHn>Kn5yk7PIa8?YV zP}zw_F}2|tDKlA&g6igmIWTN~3A05LX6({$h=Xx|g1p%X=o_K&^X3>7|I4LZm8i7~ zY(ye~&O9^5Q?&=5`}(>hqPuHyE3P+1-qP6#3WjTI^{Xb2vNo&6Lq#vDsv!uiTKpK~ z^%##sN-7Wr#dO)0+pdr?s=8(t{AG~f?wXs!;saw{l?eQlGVcNWR8;W)|;{gz57(ID$vR}Afq>hvn@a)b++Kw0Eb`07Z%ryH;j8v zThMnp;bf$4u`;PG4@uIj^(HZW?OI$nBmv)?KbQrP?J5`=OS4w6+1~{NoZZ4w1ZWn} z!#Eh* z;~u3xWU+?|tey<)Wb^C3UB1Y3-1`>hvkcHxbDg?Ru09NT)2cfA2t0VVe<9Spb!2q) zW?scNLOZg*Ds|lbHGPUaBmninkMr@!EM1b?D&^!Ix#K>ZXm2gv%`*y#y}Y`XwQMND zgfkj8$V1#K?RUCVi%ZQ=Cj#5YO!)reJ?J~$=7-nrAiPl`M81ZcvX9Z>s{T0BD-~@4 z>9H8vK!Ng#zwo!v(C}p&h>oz{eb^9>)!fC&DnRPVuQhICAUN0jOqsDB_(&BhcM={N z?m@B{8~!orPhvdK83#!}$$Qdgf}u*;e=r9(nIL{Bc8ht;zpy~oKaAtFIW0t^4`dsZ z%q-VI8OV&xhOwbuN%!5rNqlr9w*2IciGMcPv~#LUV`9AnXEU_X6<4e?ituAaJFxE0 z_3;7EZf7fKJ=&RPuMFmm^-m3bcouCe!G+a6Oxz`p!4uP>O;>t? zfDgUrL*T2a2?-<$lzM#jEyp>%>DO5OTDb zU*_#sAjB_r2E#bph`N!ba#paZLAfz{^|Tn$BfG)`G8I$v*9^L1;RLy{!t}izAsOZR zY8sIVX$LuMS*bDoo{L-L$E>~I)uI)&7zYP(p>v?leC>XJSTlx%);?@~*W9e-!D<7sEOz z5v-`-Virr1t>YD9Yum5hLguG^g8JY0PwcWBIEjIVEDpg`Fv*oi)4A^LQ-N!tHo>c2 z-yVO%X@+|4k&Ydyh=Peq4#Q7JRue}(QHokbhNMTT`FOdK3H?!xD3LJC2|W#g}+IOIvP4GG3WKJzs>uj3a2{;cg!5nm5f+5R)VGsM+>SA0X#H7RG2IetxXM$ z1^cjGn39_Mcf0J13Z09@c;JvG=U=s{BAAjmlbZT72bEbL%e^Hl+}_utv@LFJft`H&+39{?<$w{9^%;1697Ez@J@xErmF`11|v6UbLf zNhu54+K{q@Nku}Zhrk`s}9%9jyK;Y z%_pNu*-)@e3v%}E04_xVDVa4USd9StGuOWPlNH{(@exdy55pYJ^7Ovwm3MSC_Dpxl z?Kx`hE{9mfHy}^n?8IezaZI^nR|9osuDZP33rWf9Ib_+T?)WndG~N)zCsQq@^5V%4 zJd|d{>td~H(Q<0JyHckpi-}k@-boGj@{(5At{KJKY2aQ*d#}j4vV$xtdV0Rs)>I|kzsFo^Hweg8P2?yn^ z3@gb2{Z<`-kE>#g6a9Ut_~bSnYIysj+IL(g6qc7q<#z+yg~^Vc0op=nI~dj$_sF9- z^jU_$>xnm;^ksoItXd9x1`)^=x^od@WSK2Bt-b4E#Qtz9D1R zpZ9iaQqUI{#{CqSsY#8z z@srX|?1>)QvuKVxu@(Hlx<`7=zBkExYR-4KjYGAk0gKFnJ!wQ1-dt5<7BzR#nQ2-=wactqX0zS!u{*>He#x2axk zwKo85XL|;@VwU}VX7WVH`B^@W3*(O0?0c|vFn5WC&YsVazHH}fOh2IJ#@m@p-0-xdp9@5iq z28p}A$dl^H!;gzmJEZqNN(1TtPiT z$xtyI`iksc_$a#2`@Jteq3lJDOQgaoL^F2%QU10=MY{e<5|2) zQ!aF~1$=m1VIlSnVXaUH#Op5~_=yI0@BC^^_M3mWqQzVKK#1`HoUGmJwURsixIHaI$uUVDR(4=5z;Zax>l^x->g530>3fE<;FMnx7*aD&h zmckP^;$6Ns!9r2aj-LxlWq|(Ictu#Y@utJLK^Qhr6qv0vUZ3x$$Y+rj5G@nNYt9!L z@`N5I{!@Mo8~@xx5qCeL6mIbI_aKzY8XAe0>5=Ey-g~DG%=643wa9!^2{+LcebMOa zpJQ=4CA{HdukJieck2E)s!O|_Zc*jSanI~h^ksGrp)0l6@an-Nt&R%>ssr4UlHrC< zhvBM`aoD+&tOs-#=qwytbEdA25E0+uSfbD%(Q(Lr%x(>kV})@9+$Kb{NX;gj(BAC` zwI_do`2>0YuG4+J+!(9=KHQGXuqe<$zX|#Qimj=ySz=mFAQSiliYN@_i_Tzug4BAK zQj%S0AG-wWAMkcdj&MKd{IgDj`{+VxsHgXQ{DJBGNguZ1j zvn)j@%H91*N*Hw43yB)>W;D)caq-RV%xZV+EF2vOig1>KP*%8)*N5}M^z<(Yzk{F= z2f_N`lrsMDu5*AV`F1h8`5!E6zT3Uvj-;r6VS?d*z9AS99I}*=5YmVGA!+7+LgQVB zc zBs;&QYF6qkH=M+rOfYU$sj1oI4*3BC|1vrWdj9Nzg<;$+PEzIJm#8+^S^8JWu7!6q zx3*Z1Aej!w=CYjyktV+zEwYh;YHU;#L*mAwEhE|GM6qxDy$&h;IyWN1JXFS4foWzvF2wq>Lz$qh2i~=l(%?h=dVvz)lL!od2dX3u^a2`4ry+KJ6pF! z(EMUxj%%5uH`3&wPlm8GxBgI@>1xz8zjx9GhdyE9$QzhCClWJu!qlM=j0B@d-LY6- zVJ;(?UX_Tijs?B!Ihs8WTJXdxArL>ivmw5Ox_G~{RSk22R%bCXy+*Qx1})m|QlpGq zJf#d0xEn~T=ehkZOVRjnJ{W8Q)!TBKY33@$(ZX1K%rAJ;$E(q>5NM0n!Ft`4a5v_f zb^5)BY-zW>#mpw(@i+n$+%IgDRo`Cf4-Mj2NM&|;%WGLjXAzG^sP(q;ND z*0K8^b*9zewif(9o=bl+30y_T#kEog1|q;n*G!aXQ&`(YvxxbJ3?Q<`_m`)DLJ5Um zec%sVLNda9f9X*0PyT_#Ec6&bTr|zw8U#auBt=3JK5i8Jd~-I^Z*<&~bd1v?kdfri zuGZO(^HM7UZCrKR;f@h*)7=R9J?hZ*S??b=y)S3~6w65rZ^I#2++2%<9v=L2k|CQA z=P+R6EpH(_h7QUZZp%p<%`*_0jF;9WB8gf7<8AsU4+RX$Q-p#4`~5CtEWaF6_XG{c zvaY9VFc7ZG4!6%Wv>8}p3E{}6lU9Q1Ik*)Y*8Z*f5tM!D4 zUp`?R=U?Ll#Oa--}JhqQsnNG*8N1i=%+;?RA(v6#1jU`B#-=xW{y`VeC@&p2(>$<}{dxBkzV* zBjBCz`c0@Mt0yk>v-BaSlrl#0P23HALzz2(*i^(H6#wWJP;Ds@Vc~vW`Vsov=L#`c z8w^AP!_4a9pF=y`qdPlzt*bM@gF*`W;_(LYv>7pVBMkA>CWlr;y1x4we2I|^t)dzJ zn|O;L9kU;~(Vw)9j~q^hMJ%uv1(_lC>k@`def~&5*mtX~oj7~^KOC#h1lqP&VTPrX z47-1yMS7znBhj~n;hIMHV5mrar1DueTWqto;Z<=pq<0H(VLe3mDv1WctdkYw9;UU0 z%r7Tdf)DZD!C_2~#R9U`xB`2Kfxwf@ok$PK6P_R8ZDp#N*? z>w5@ndnYyqWT|{EW`uuMicCQlqNUA(u${;9@@p5 zK*-0%j3%_QQwl@UZ#z^%CH=2{y>aMF-Ljbs|8AR+cTfwwY6S>XM$_hEEct^WAIx$e zRc>yp-(>W&>(NA{SyIoQ_gSjsiRhIo_{CQ_*R6pxCrJ&cZZtiON!w^c8b>?KdD&?j zo|a`5X^>vX`kgk#fHdN$7zZ9%Kwd?7>S|)oWF!A%cy~@nGcQ%D!leFqrKh3Xt`vXX zRa=ku#+TRDo8jA)>)qu{A_vYQBCRE?^?)Y}Bq-*Iw)*~aQ1tKbH$y~&Tm@UwGswnF zAE&*9;*(w6#rZfGzZK>5Bht=mGzsDI`Ul{Q+|XJ5sM zC@L*ZnDnv~dPbnN=l=>%?Jl?zC~XcLHYtLaqJ=y@v2!=6nnz&ih?_Wa8o36&h*ff=Kz-K=Hg*6_~n7S zLw^Yj2G0~v&at?=rGYtGl=bXLnl)@F8@x@uoT){oD{gJIC=pa37uLVjiU3^i9up^8 z)FZrHPF_Ab9c2(PuH4i@*a2+NwsnJ=S3JF2EjjO93KkI==j`CRiVE&ET_uDiHdaG! z#wAZIo69zHxfmilE)_VDF4FV)(Si2Rd~vZp5N)z;j$Ce+hA$dWJ=AhU#h8S9nChD9 z<>RdSgZ5lm&?p>l%TOuEQ~ontG;dXUK->OOAO$beh*|}BXw4@>ww+~R3DLU5&iw)OwTtK0y6kuyiW%J z>i}31O*;9gD-2vP9wD5CHga}!rMtiwU(-(`RlH?KG1Bl}1fvyoMgR$W67;nI9<&R) z^_Z^~LQmABB=9!&Yb@Ngn=`*fX&TkOGI=Q?fmb{`e_HN%zWE9<@v2L;?Pt+=5M4O* zy9TNm-0LT`4W9veP*@I4{xNWK2>3M%L12XMt?59|pXCZ%WFn+0k_3j#V-W*LtStFF z_W}-h+6(uVX}dr27w{~6L3flsa*B=>T>14dt;ixd@tIe3&Zn|WI)~M^Vx4~d> zPWjao3dzv;zG&-4?U1S@Kl@K)1<^>x2wpE)*Qxq^U=c8Vaz%PkO5)P%g}qoLf@V-v z6F;#}jDV@Q?EC<6{!vUw;wJ1!s`bg6UHOdyyIxiL9aHT#;}!(!%GC_)>YjED5d2et z3eheg0A;%DQZP4|n*3xj@snrnMdUY*DQHEl)f@>`l(*t{2yFq^sLt}?x(Qw+TpJR( zlGH4s*&Bet#P=TbJ#StbM9n0zOp8SE7)_+&uv>3)qUI`tIZFdD8l<-4>C;=)N zA@7_kSQ0e=$A_w?RJw*HBq}m@(~`I6_}J1fq~%Cz*6H0ikn-Lm<~+E34y!KYf@WEr_#v&h7;@DwH;M2CQdiFPdVSC0KL}cpg)Dbq6J!AzA|q zT;PL&oTMMzQkr{0;8pY`5%8-B8q7|(0z}?u^VX=;xXvYUiCEqF@3Y|fheF-Nc=xMe z^%RHU*DySkD!E>2_+HG1t<^_mV+zl&&YT1CH*<$_-u59G`|!GT>T-*aFT@o52^x)e z6T2&Es##J`;MRs=?XZhZsVfns?5X9tbGq5 z5NAuc>#~sR=cYi@%P}lz5ue-)vxy`aWck?J18u}JP)JS;VKxy~RrIh@i3+|70=c6-bd-(Kux zvYP4gEyrzAC;IPW0{Z8%x*FX_&=ISrU!qSq9Z{tWC+VTCFziy-F;|^v*OW@$BE%OL zi%eXF%Kvf!Uf|NL4lBj3^L<5z!{f5a{|mS-ny{tGkzpUMJ6^Zrug zg*;anNYRJ?52XIzWId>4mRiIpr~e~O%@;&5xIdLXPzIrx|6TmwJ&6jyICM4o7W==Y z1y;m?D3yLh<%IvYL+Hx=oy?45-~P8W<$DmtXQ7rNMeKi%QvfrBZ2D5D1keAGRv`$Y z)V{bDIhFmdwxP{P2*cmD*U?J-Z)w5{QXtCro>(;$kU{=;Y~kNMYlovX(#OR)_&?Ih zKy!(3tFKQyUl)kFP-Tf<^*62I$NtRpbnxG$M=~X%uRDtY^(~Kx$oCb>7xryr={ept zZal=&rTPMwP8ZtYfsl|VE9PUv3t_XHd;_Wkn`fI_Tft!{$n@diT7>3ryiKTiX)6EX1-h<@F)*O@OvQqd6PfOkb8?zw8uI7 z1vtE}BcsRT!=w3`Ds1PeyUrDmYo?(5x9$A)td4H5|e`q&pad(sxv^b6&D?oHxxB@{AnksXg-be zM+{X;^Zh_UhuCIt=;co$m6_uXw~q(h!C~qQpvQD14+7ELL!07w{mTM+P-ZiGqX*EB zSF4Wq7s2#c?+`)b-TFQISpVx~>CAz`dzsW@rld%6$A6gZ0vx!W(Z?9W`{>eAQb~8b zFaek8+&DW%DA-CxN-nMT;|1rjSWeAWdo#T6gO=|PvwT!2WB|uRU?5J5hVBl4qX$i1 zWJa>*)eg({y#v1M)(vZDNNcz6Za)q?X6Q0MoIK>g>%IN!-=*mSk@NZTFlqC--(O#j z2P}U4`2Q$-%b>cpt!o!|cXtgQJS^Nof`mYVySoKVs!_k+nv7gJZS&#Gfm zr4ecBWLq=j-){hs&cQ|$s2U64{3Wj@0wxJUhk^8?%_tBLZ8iCr)DC99 zhbE-OVl3oo_o!Z7K+b89HH)sZ_P9$Lz8^k&80^NZg(I5Am$*Gye4LVJv}5%BCe;$* zSDqk8c8!^CVQWv9M8f7!vd9N(*2ol_#lPnNe@)v$*OHk{SiJ_nham>~WADEUqbw|Y zJV#C})XaATI1kv_@8KcF-!8j`R91c3^DnfA!r*h*!7xvIOhj1sg@qos!TFLm#&>?M z8kh1_tZo&Zr6ZDQ8ZP6*w>H%cOvOIiO@7C~@eslH`|E*nRcon~9pOayBB@+EV;YXV z3aqF|mW@n`^_^Io!L(-Ml?MC8_X3}foms)Tr6l&HUa>|#3m^{NJ9kg?Um-B<$I6Mt z(0=x*S`EQ~Ow?>9GULIF4e44d;7#TCTBwH4jETV*7-FQ^S`W+Ec~*AD~MR& zr(A4$EvE*;_5%su4M*BKK2$Zbl%f4$P(JMJYOYkxeu^2yeqsLTSC>D~W3atqW8RSW zM;>7g#{+pQ&BU`zFdFOYE4pW#=fUhh&c2Yeq8b>mnl{n}s<;?>NEq~zJ(%=ZZU1IW zX*>0eZu7V@_BJNO_-y~}e^%Jc2Z}E=_ojnws-H`Cz8%_&n|X!=on_Bg#nMscBz>au z7kHpc$*dXfr~j4VIg%;N*v0b9mIiYMF;HiyA}yckZaHi-`jZ}wYh5{PwnEPfk4T8e z{|jR3%Jv}pUO0D5wbTTlf&IFZL<5wMst;!>^a)cIrlu&e_F*ESwK9ynS=77i<47QY z0fFESV(B(n$Lo;4+<7stN@pCnZG&7Ffjb?)3<|$lq`7 z9b~s!v>kFDJs3*zte}yf%(+_u{v2_G4L?j^!b#ji4y;wQ+_F$oJF&j7F?43xyIaYI zwDk)RKN_)+xM`PXOP)a*;xqO+9DnWX`MD#Z$q@>UGgM5~4%!`&&*Jd(c(=VBUtSns z#aqR|o*ol<6XLB@^!??k1CiGF)f?opGjF%;G~&V#9C79a<;z1)l{(D?WhM!-YUNj~ zo~?-d`Aal#0EW+K6dM7Y#KMz*)cC30_mk1Sg(W6zJraCVkM=otc-MxmaeMdz^Bph> zw}4S7`y`;l1$&HXaJLb9>E|8JzrBllnW^STWJRjT|K?Tr*9!lo8-46}JS)w7X>Qh( z88ZB;-X{77Z)&IzoKaroSayy%8cBJA>;k9ft0<7#!xHkH`$6pm9iZh|1t+!!{=vCY z2=13>=}_*hrW{5Sqd>yz;e4^==Z{w79WWwmAP2^biIK$Q+K=gds2__e5B;pxYkrH|aST<}!m8cofuMQ;#Q_Ksv zn}*!gEqlcL0(nOCfSgo~n{+0&4iAMDGRi2Sy2L{#;2e%ln^Hwk1(a8MG|G^Yu!FZ< zrZ8Z1Efyap-;;0%J9)TFs1UG{^{K+F1$2+BmbQqE54X3tJO6lfU-#ogj7c{D zX>PlmZ_ZOAWztmLtf<8JYB~GgtQH^pl&QE#co-VoZaC&8Evm}X`{5BCB5#k;$l5NJ z(>B+dkxKm6qo_d}!``Vg??+eNlvMEwr zZUDBVfr>Jn&IlYs4F=5JWo#0L={PD;d!)1&E14_hd8=eaKa zAN?#eEi9yz6iDNYliI89sDb8Qmy5paVg@(t!52)%D8%ELeq1XVQO*eR&wO5K#8Dtn zDJE6si-fKon=sptSHdi0H#@Fa-f+M5ANTaEF+OJdIM)+ulC|z}IZU_kGHURB(Gf1R z^`++*cT*c$D7KCkvK{8wc+UORiEF=~c$M9b7-C6ockjh29X~#d5BdP)qP-E^f)k^g z_)5hXE(9Bt#nA~xf7mWV)AW|$>(*F)#;<|3YE%2#ITe^g6t3b(%z6m3Vs@_tf+x03 zFDJB{ijP0o7K`~rwU~HVV2Ecm)M~@290u<<1}{5yh_A=WtYlJdbhBBNAV$@c!Jd*G ze|y8nC&-?KAsE7Lp(5HTl@4JnYJS)#+}87q{O~6Rw_W$kbUJQk%grBy9+8ns#xeO_NZhhYGvgaJy#!b9K5(YZq%8X_4zi?L0e z&xsX*VcEu5u_)n%!@|Yq2Zqv_unV0pRnpI}yY77fOW@*dijSCtn{F1l{$umQ%nb3XNCMIERSGl%-Zj(J5Dh5u0kZ+^5daEk9B%qv{a`v(VY zDUQ13RPz3@aTF3q`{M2-KBi!U4G|yd^)1QssG=86kpH(@9rLNVU0QnLpyl(!^`-?r z>Q|sBQX}HAHRwy7JFcnCV)GxVM}NPs%P1N@o|o*K(Dswhrv{CjsuF$-OCr)2OR@7? z1zMK=+KpO=M#xMY4T)P`%s^E%vw@yAb*FZIm^(Suil*4xuA+Fl+K_N;49RxALKkEa z^lT_KrVl7ki#Q?(}kJ1k`0ENI| zR7$RHxpv~404{^uQcWiv_k5*BwtI>&GJ*V{e9mzi!<8HP1p8)T;{4Aps80(uX&3B+ zv+_r4gmjhP2%C++b6dE)=&W;WUFIdM8m&%#D{C4|t9SKJ?w8N^R|EE|#Cey&O@4b_%^;K3HHiwW zrE<13^~*rnkRI6+-5pDpnN3Ig$}N;pB9bQa8Xm#DD}kgDpIw|ar^Kawu&ojx9-`u&iGONxxGnj zt~`RrOJ2Z0J*S9VF1V_RfNjjqkum~59c9r^ljPlALZx8fSJZ|UhD4q5Z6kF}js6Tm z8!|;$@xxKs?K6CAwH46dD(=c)4Mu@q9fRzA#%GhjK~g`%E|Qcx+6=cCfyX0ubp3W8 zXbyt`EQEqwVW-=Z<$JUSiK}j0t++u5jx-7Vsowq<$|64{8Xkex-2_fmn>aQ*eWtz=L-#%h)raQxy)qv+X{OdI`Zm9l6uJS=eKs#kd#q1BR?YL zuCVWpc{ON#MZ_s?aVK7FESmVb>e>F-F6j18gE_;Zq4k(olWbGwN+t)kxOr!fEN)i zFD)bKlc>OR#2Bdbz07Qvw;>mdGxIFYCC!9`uKt&2^pS!coQ6%2)JBkbXsE3s&^mPMa)h1)}C zvSi(Ew*NfhkSoL;notyJ#?e4I3C=w9elNBR9Z^5o?(i0&>&!r4EsZI~ zi6#j5IBpXV5;90@CNOIZEE3>Oys-kTn$BUQgnO|yU39EkpB+?dOtGyJ-6ncmXNpy- ztyTpV%5@;KNaLp(?2O3oNCn)I-uyMDD@_e&Kpd~v1aMbZd%k+CN4#LWnN3#?sp4IC zpWKA=yWU_`VJm4mQijvUyQ+G~Wf6gjoMW5pYEN2SuRN&VcruXt@U0po=uWW2w^DRb6H@c5sc9 zVB{v-TVylM{syZXxk2g;?BVnP17idG43>C^D<5#SQ(`gD>@uOOdVQsQp|?V!nGgwi zmnLW%H6xeyu@LrlV*K@m?!?iJM~#NM)CGtyCTe&hrdoprlEU;ay{&Sq$PEQJO~1-} zkQ~2Ux$C$#Z+6!C?}u=Vo6H$`;o%iK@36^xhCiU9gOyxcQthm~pT?b@#x;%IOOi3>CWcshmK-8cnf_P!43qgL6%%OLUL&>Q}&_o1j7H2Fe zb`_b@(q*}ST5^W;*xJHXzR2bX=1oEvjm1HGE;B9DZh!T$$?YhQg1RG4MYd zE0vCuK>1SCHS=X|bIL|PI8d1bvjdFbsm@20v#Y9>Q~9SBqx26_0LWw^cli&C&S2a% z%g+t2I7y`?CBuLTH+?G9B*gtuc-p%~(WxKG^=qfY`4YI>xRa%FF?ak3*~g?*QHiaz z{#9ehrgOAOBQI&XilPk<$jY(%Z-;y-#QJg3x94+%%H7lDZ*)`#IL@OpDf0sKO`L?9oV#D zA=P%u6K{(=AP~dPzrdGURQPQ`FruE7>*LkrbgoMdWq&jmy)%+FnD1@$0dtuH>4Ev` z+t`E5Jr{ zd{y`hI8Y&N=uTN3v}bngIW{H28_+^{xX|+Y;%f6c#6B8S4Gd-WWbkLffp%C$1c5Io z*<}I%?8B+$%j?iV`!WX$4KS3!+s_+MTQJ`fn9uiy;ZrVPz~qtrRV;1BOD37MES(NY zCL1(a%*WT1uo#mj;n*~q5g2}AZEFupjY9>dB?$qnOC&3mbh;S!j_zc)gXTIsQ1in< zkz2umiOZTdtX~+SzZVr{1NMuAbF|HJ!vWyzlMv~2I`78aPt@|riWGdA3*i1QJ^{|L z7Fz}}stlCo!}eg}WUf@~9^hTX^6~*EAm>0W#drrv;0u%#W_Y|lJ050J^cy`~?d$4? z6n=g54n)dnmZ)^V7g_hF){@U@nH`%xb(iHln96CYzMRp1gA*9id_D7#gfhbkMZDM_ ziwyO*cD+i>qcX~L_w`Y^ocqM+7PeE5$10?N_)bTCLnSIyR{<%BXX{Ao*2 zX)^X4h4Ce3LXIf!ZrT%00d_y4h(vBqV)xfCYsp7nw0DuOwbF$C2vt=Uh7`F*@U!e2 zSx?X^$r}P%?0PzJ>0w%3Y03f{6=$Kz;7FE3tfEbEkgoJ5w+`e`)F(@yl7Wih#ve92 z=_~@-*-h%EW3FJ)`LJeKgHVKB_Sm>xZ14D2cn| zj+&(1U1mS5D7Rtc$$w^nkVib2^XyilGOJ`fR${mnNdi$d1e;Au;wP9lZQi+z~NX zm&>_dW;?dR87w;E8{^3(duZFIFFFovo>~Kc;|ktwV1}YH$!uGhk$7f|gg&*Af;MLj zzADZNp%cyCO&e6@#RM`aU47fT+Ey)hzT6p)q5k|%oL$g%>*M&YaI%5i-jnC!F*iA# zaN#syu{E75&l=kk&h&W}fO>b;{_$z6`zA!3_$@sux zs&Lxejf82KN=Ey7+xnVUx9XAl=46B^rAv)oGEKmxl>TW`_iUTk)3yf-?U#wtQ6PpP zKmmrNz?QTC@U@yuU^_aty1&Jc((w}0Zi+TWqSFmoy_wFEX7IT!e_r9_xPf?zzDcdr zg?{J1k3#!23IP0Sgc2*FY6b^Txse|=M0-7+`+LIiaN!K^3Vc3=AoSY?(uOK$q**6i z%xMxBQp3MKL8A(vGd6W%{kp+E_V2k~T20MOtpAgqPVM3m(9K2YQ^LQ0ezo=d|Ej;E6O282sSikQGE1FVL%xY#yMQEQk$=K z7?NH?lO78y*^Kva{^8yJq|rEINkTY@xH2jbZ7=-k z6C}Q-gZq0)q~EM)=C@-|A1W@m7apfUW=>UZBJ8L>UWgZGYmNog!y3gdtD}%BqJoSV z`)04$2Tkm%o|CSVR^S!o4L<(_9wb%T&0zi$cwj_*=EeIr@gOG|y1YeThOiy7!*$f; zdjDx0uFmy8r%jEjQR$Xuy6q+ zn<%SH+)WiWWEa3^2ET*AYT_+L_c!gJH(OZ}Dhta8#ZPCRlniA_G7L``k0=whhIT%2 zfZ=I;)ra*FiHX!BsWS20Cf;Q2-D%o>XcjoE$zzYn&P^N5&&d70L4N>~$^kI_5R@oUUhQN7=4^ys|)Iv=}{flP0 z!E$hus(Sb<-y{tBBDV8bvAb@j&WywO2*=2M?w!dG+Z#;-8tX(H4>*cpOj$b@RTOe;e~R1~nadt?LU6`1KY zeom}a!sI&4In?Hm0fi({HzWjJOH1m1j%ybS0F9?>D%T_0UJ(RG3dZ=QBM|4t3!A(U z2xl87W?eJAD}k$T-@#7NG@h-7V&dlr9oy+_m2Yj&qX1p%WPR|h$ztX8;uY6%!13?l zs*xB4xyNwE1@4DDlIrk1aW1LEBS$SsjSkGM^#svYFM~(d_&b0KJVcoX$skc4MwI8^ zS8f{P@bYLI+K#{+wys^T^L1yw8~p^Gps~Ld{9tB!^?lGSkFUQZC2X{QEWa6zxG*7Y zsZ1Z=sop9;inu6LLN)1)2%^%3LBd`*?SU-I>mpthQ)9mbJXNPH$4T(IQRQ|ouDZy< z4rg0*88%H-s4&(xqE@<-L71S&c$e`*ji%El0i3z#Eig!fnN9^%#C^jXCLz3`u(s-7 z!_S*tkEPEoA4yKsHvi-?G4v zJL_CjoCih5`-Ub9$yq}X`<<&sLITp}05FgKx&pS-lQpxN3{V{o#|yy%hf{?LvK8K6 z;j6mPWNSFI+rY*JMbv&v0*D07n`p^;Qtd3_g=xLs2=oc@RXU3domYl<6BoC&odOoF z5ZHE26oP7{60pRW7z)EqwzY9)n5mn^1y?`~-3zr6lak7zO|h~^r>J_c8pml-7Nf89 zjmq=mbr-z@5!b*c%?KeP*&+AI*p_7GI7#4rc1)tzqosh${ud&l&z-DVfxeg5)YtGL zQ~THDXt8_By*IYBMU>GRgoU$eiun9K9IoX3l&jS?4Kr)L_gBIliI1cfi_(_%ak#`E zf7(twPv~}ejiZ{cSKL8QdR%lu0Afd?2}$`WWIX7~x2@UnRFjS0*P`B<#orz72JL0G zM2+@+04jYgq;CLKstn(X=c{`M7LLSs)%3AX+U=u$@R)vS0>9|A2ccv32cpqSCuE?k zFST-Be3i*w6_RX>RWdtQAA$F7)tNEu^2{fpqF7=6a=N!e)?utSv|#>>Z~vzRJF39> zzj+Gxe_}P^%_@XuiX`+P9Vyd!rQqNAhq~+Lb@c4criWuWq(Z#5 zQ*>jKikU7@e%|0=rifUs%Rgg^XA|E~CCZzWajiS(x{#kG2*z-1!e?jz%u^4v{yA3( z6^~3;DTQWsdFYp(R(a<4R2fU0pfjMLMVtPyj^gNB*+@m9V{xo8--EoSm{dgy)aQK2>jurSuM>UKum!q_K z2Mg+&9m&8^&-NA;lqI8dw<>-GKhB<%O$8`?FlysXcg|n>vWk{O&dO!#@9Gk+a#xK9#*VQcCW1wtjLidno}chJR!eu z$bxjySx(5$b}Ps!!kYMle4H%!{D;7Sd3C(G4P0Z7MKB&lp(pXjkMxI^!irf|&&! z*^|>nN}(E}+82-_pkuj1!x`MctEFQ?wkj|}Q{#78`%uZ(>i|(?Bl~Biv;-uv-y|h4 zP-gl@3rMIubDX{f=gX(IF-t`SYOi>^h&;D3N~9RzcTd(*&I{zGc0pH?RL`Ty>P+|m z421|}d7&uyyd%Szw@^UxihupU4RzUjWJ>j+3woOgS1TQX0OE>rH2j^dHAp+6sN^LC z&zz>VQH_f=aeC@G(@!LLdCO)bIoNJU)e4C3$?w`VJQ#Cb#Y=7F8LO{u{Gw4Ld`rXj zj-7d~hYm6$HZu&e+*`(q_q)9l8glDD>h*lVLD<0*@NO4*RNgVQRcgNi(${BQD4a5- zt?|PsI3b)6B_~9kH&q_h$IG)nRPcFqWx$5G?kob2{X~bt?%I|OhCU_hpi}rMmIO>Q zriJWG#?_^!|1q!zmrHe_8-`qJx*L0U3}Kec&n}2BaXaALv7uO;SpNUYTk!AEkTA<2 zw(9BVLA^OuiYTF6%5;A@tYPPRaq?<*mDhCcPbud{e zCkcX6xZEAZ^})tclJIN6bpOf4+|h9bxiFfWOO;db=L9#KB>|pX4$b)J^4;@snZ$cY zz$nZpjMlxOO;0u7%k5Izt4cVsGCJ>49;t-w{AZCyJvT^B-S~i;e8gMv3n6omW~zd6%*BSa`>xYOB1Gg-w}C^4B6@ zTo=~|)0hMXM=|*YrsQCuu*&LfO@|_aC5gs#W}OG2>}eR?tEVN~;bMoLZWS>Y%y3yJ_Ov+QRb)r}{5za_2%M8v zi2qju+b}Scj(2K4hdfOPZ>caIz@oX8);o|K^(o2`Chs?)#OROOgPrf&(&S&B(Z)2u z)Sg3h(l-Y_Opk)FcimVVG?^V-MzS(R-ikr~;hI#0f%ww_`p&ZIb~(IJe>m`Q%d;O+ zjcc8wai!Un&=4~Jj|LFS4tR;*UYFMVDT9c}P<|_L055oaqZ1=(@Qc=2^V4kTx6?!n z!{3bm{8}ccAO6m8ymP7;v{T<;JJJi>A8)3I-=Pe*S@Hw)=|3;lT`j*asDwI&;@AHA zW*CCoRLeiX0jQ+R2MCQ&a|#B(j7AryjjBG_#wQ|a$*1EMtr&PrfBUEJRLFpGZOo8_ zK-(E3&3$7|Rnp4r6I{xi3xb-Ux4Oy|#pXi3!Oc>>9BK3nsppeCGai&P5v7IL`$&nG z`27<)7DJPHy>JU*n*sdV?~q#jwsGnBGdKJD=d*U~Ax7UNUEHpgSRcKbHK=(vOyY36 zT9beXQPG>t`EQ=Zo9FZ$P**eDB(48HF;L&|WCYpr&cfnAR8pK?9d4@?bus6E20&i` zpkXLvhUxTg>L;B8A4qtB5KM;hGXy9%JDH0j%{OTVN+YU`MoB7G3qj-3P^@>eKv|?s zB@xP^(_U6!7e5LI*!r0-fRhf5f_>W9V1$kT_?<@)B9QE@^5ZRyu+J#_RTRIYqr*=v zUp7t5ZRmTF{Er{iJW~j;(MJn4gD~t>O-bFNE)vSA+ue-(lFE&-Bo`A!N-S@Thv z;Hwz`QtBuD@!|-ywgQ>V7X9V*dV8V^2z54AyROM%B#CS0_eFoztNrJ06d1l)Y{y(z)J zk-QNg1Z0z-h3~?Gg3xqqoM4AUt&3UV*dckKI$i>sw85-L`ETJ;osRTEU4L%DcF

zgv%mp--akq6oSXcL*T?|j~w|to}5f)it&F!3r9)v-mx;BBMFn<+f?7aLqQf&kx%H4 zr46O@r#3WnW(y5O!qZ`TZ*(@w$j@H9EQ5M(y@w|Y-sMfEoWuHK?@Kga)dvwUAk0je z?9Fe8`laj*CLk%D;{o_RI);i@#0{qf|M4CGg?mWg3habLGLNHzuU~X^v&Ra!Etiy& zriCz3*J~vsNkp8E$Fh9UYUOWaQn`Y2EObVZm^g7vHnteiIBsV(T}#m7bOJE3v8k7~ zTlXjP5o6Jl6o!)6M0qwpuA@^*^pVXRzD1#cNIX`GJrWtf)~7rv0l(Yni>Ca8DB9?F z$~@q`8D+D84}-G?3&CQXlm!j|$IDF4*4k$%TgAa(U$tE$!4V@ud%z%*$Vq`n*wNKS zyC1-eYgTZkW>F{3%Mav4iLmD8uSPc>@?Hff3Cs&%7v938hJs-SeFZXY)rgWsdfJt4 z_qJxwUbKBd`6~EB2g@Dbp5F?6{xhq5X?~-;{l)~FrR&)9|DII5_~4RK z=7sQlpU){HK@@%tNdiQC4q-qFf?8UhEKW429lh-3T;E3}8Si}o0?tJU> z_&(Y!e=*UNWu>IhRoCa{lnG@(IDsAdFuBcvJ48NI(&l7t9Y>O%3ArtE@9vyBgdik| z@_+p@ZI(IJA@S4rO17k13zpE6(&E5=L77VF2f(WmH%6YMjs4J=2;QL|?eb^huYB)5? z2yprS&*!v;0L=VNSVQDdOsdsEK!`>dsKo{{>+s&lp|U`Mz6>z$<1(pKisc47Eszpz zvsWjhg^^zY>jZa)o5(N9GFu}e^}JMe|732f^m3&@7{~LCZVCiHK_mj;k}Ni-!_iQ+XdQJ1Q%Bj8B2QCY4pQ(;0h*Y65Dg zlQ3N%W5(4aLnC88`i#VWuo%*d4wvEd?{6GB9Z)*DPzt!kxMMMz#K|@ANJuv)%M7)W z-CTwBb);Yi=VB=m25sgsD$Qn>MUJSG^hwA%XgYEy5A&DuqyL$y-sWv};Wl4fmjpZu z3pk0fhz&YJ{wfG#e}MUg;5L^!uT9S2Cx5gY z0iE_0jB5kZaR@=16^!VZ>^F!uxfXC;mYH3a+BH2&k3e{-YMhjxN9bX;N$ zVlupVWP(+f>jQY1Ds~@GWpFjyp0E?U&P>b4kuE!2v&ZV6?hf4i#(Tu^#7)Qj1tdqE z`22_G91No36YLmU(cF&DVFP(f|8+DTk+v+u6?EUv9iFmt5rk_a|?EcvgFk0QFz9w;xj#^` zdN=!D59MtR$xBwU_}iTG&$G}#|B`ZlplbJS^?&`ts|!%y@>*sEfdKa3$MHT0c`ITu z8!mMFhmG{@q@E6eN|mS97I-?a|4dqcU)67hw{nzH&isp#|Gt*9vbUO(*9V$Ru>ZPx zKrNO6B_}O^W_}LT{loYVoMc-o2~gtmdYI}3@xLx7^Uq&b|Nrx1gyJ!Gnwy$_GbH>U z_W;2=G(;#KW9RYuP!blEBo|O_T8e1Z!P5ouz5&RD67l>6dw?l`6Hp?laSFEpe7V|q zoZ?)qTpQdOz_??N%9B}HS%rj$=dG=+*$O{DKNs3;_V}^Ba@pn|*&oi-%#6=!dCH`x z8S^fNeBS5nQHBX?0Ni!XUgNO*k@lr$V z#N^~_Ml(BjWcC2T4SbZ)$2snKM{x->XkmFOABM`Xdhdu3%8<&v$iag8tPI8s#1Oal zIlk-^*}fF-LMYa}LVPHE5P~ZETYSMqy!^IKZ+jLMKYW}13}MK->-=F_!;$Z{d3xVY zF3oi?YdF|ltRI$2c!WVP^7S~?E!+I)MX3`-v!aRv!U z>jQWc!;5)AfOx^}yr#E(-b;#_P_@mg3FM_|1_OaOD1-Y{fqZR&(dzS6uC=M@Z~Rn$ zMBD-1-Jh|8NrEJslBt&Nw|Y2-c;g9)T>~G~d1=JnDrwECG-olApL^PC-t!ki#d%?T zf%ue(hh}ZxtXjqaL#Nr3YSp5m>9S94GW|QA2*B}YTPpMd;1!Kampq-mNBkzuZDXj& z8qOaYgx5U5x4i7^lbrD_Mg|5AzwYBNKiics`oyvu4)t;N!*fgQoeeOQ^#RrrOVc`c z{mS>cU2rN*P8DoIu2*~Hoq?#h2W48VElWUJ`~rxM4oH%^Q+YlgYHcSQrAL>wJPbJP zpQ~!w_EWzHNK0!xS+Ew)dE@no%yItbqNw~-z`NG$Jj%21fj$%kSJNp=9RPW~cfQcy z2f}e@1l5?~gUpRX(x3VSZ8pT%rPfuu$(lAJ__lythT(+>P#Uz#0w8tLkqEhlrkVk8 zqU<1W*!_7&L4Nww^mOJoiZ~6Abih(>X3yx%@r)x6rR9(=G38?VBHQA0YaXJaGlc0 z27ThK7YM$fN7MPq#(lRM9y1d;xiAissy>o**w8PT)Rgz@1JNFbC3OUPm~xjuvytu1 zNI{f@Ygb=b>`k;tPM2E1Mxk^A1e6!9z&mGdypf!|&!hC9WK%fkmG-3TKhQ^>e*iK= zoyCCp;^#nOeRy<9RR4HW+uYg434-m-yb0vpF@03a4PxsNtzO6^VAU49noEk!*gTrtbDYB1uN-cx{Iz<&faj!NOIy_LeI9 zR+PZj)(Q|-8?Gik`>sm@qnh)1+eKuLuMD6NrHrc6u6n*UJGW}LL)g)Jp+;XVf0k2F z3G>V*7EC!m;4|?U`WR^+Mo0Lrq7p@kxjJoZ)MNImvF3B}zu(Y$%rnj%wk_5%*V_{& z;D=KO2XBSbbSer^N1Xw9c43Tu97u{t?oAJV!$|n=smuvhUd+mxzXPs&oI=g!Kgm2v zB02}fN@eNi2Y@1;bkbR@wJ<{>R+~A!o70QLk9y<(tUoq%crvdQ~=fBaJpg<+T-?vkWvjFhCAIsb5`9h zoHv}j-eQq!(nvNFGM0lzIBXM0)`i)~5dakoC`51(EE(rv3M`uu@`l|k;ULRD*6FON z04)dKmsmhkgy)NdL;#2JSet&k*J`V0E9krn^J}An1rT=*R~io*2|RSob&;4#qEx8f zlpO!~NHV}U!)9BcMz;dIjs7CM-$ed?5#!q6Y1Rk~_3VLy36>+Z2EY`yHI^mXKI&lw zx7p_UJxc@{pWo$2X|bjWUclBZMxCvbLU38{qzoQ>&oe+VJozSm2ExQbQUxT zmizVejbb__rhq1^BwPu3OFEy#&(^1l!OLzA^;Hvg4E}!Ha4|lQDPogV(d2ETu>Fo2pLLIwz#;@KWYE#6tRjlVl4ET?TRyyy&B(A&tfDu;PIw>`8Z9iWg3TE3XhSAy#s$|)k0PE6 z4ADwSWgfWzx@!&E^?J>@^#t~h0)Qkl8fpnT3 zYgA#Js8-%*^FCa&%v2jM%r^adj@G4KGaXvgFfPu2^vBg?<(n_R!`$>uvnXvm`LLO` z{k>(_DspCXcs#vIvW{b;OeO9Puso-DlyefFHv=>(qy$HX-UNRSJ)BX!Tpza3 zbIB(Db&9SI%I|WEjslBzxe5_!a&y!H8Xj}=-62Y8xeBoEZF{67XXco8a$%miB6#pD z4Bu&s^6kQaYL}xOpy5?U67I7Y9!nVJMk&yFz@m!8ryL(g*LD{yqL@-Ung!7XUYw#h z=)pMl8lp>=(yjLS;uB>?B6BUHa{+EM+OG4JVIbZ~TqdsLrzD|yDfoMps9_D55w$Ft zIlmL@E@Chm7&u4CdQ9)T>*YeZg7moU2Y|(9WNpK|E0PB+ab>4h_%?bw+#Ye~1e6m| z0JJcP4WU_7Qnk96-q$JKmwVJDlk{d9z^rNG*Bz#Gee7vh+_>m1^Q`#Qz>$;xw~`Qo z$Kvs>_lk~|adWK}DSp3!?MZCmUa=*3zZDxENa#yKiJyZ7i6Uo5<%3&gyFDP!BG&!+ zW5d`O(Lz{_EQ`C!l1aE+7!eKljMwcu%zo#GHpp-|HTaUq3WF?0M{?HsPcdB+j;(AL zpBYTmlNkeLBM=lwF9sLh&H|f8;CJYooB>Wk4uXyF(jQ!MzS2MjB)G^#VUF8>^4?sj zAp2hn%D-1@K5sqm0`cnv@W zxMU*#{T}^GJ=J4a13MdazM|)^ZwLQN2K@C=cd$^!*%0oQS2-n&YeFj^zYLY)eSS9r znLtCc?hKCy`rq$Vavz>9M^oQ3dKutm`6&B+RK`GU2a+nNE4B!sLMqbrfWpRT0OML{ zsS2lPgePaDF$_D(-q_^y7&)J~<%N3c$>L%A^qZIk)=~e{&G->$`Qr0ntcu*pSS;*ZBqE+Kzy=Z9KEA)dzat?N^b~wdQ9?etvIy$xYuOpiu)5Kx zLuSqRj7ktyVx){Kh~hGilzNpKtKO zVc%39oBwEB=f5@Xyng|(X6R#*i1lc`fTn%}%0T#ed>8O6#{n&ulHG3PUSFPNNbZz% zLgfd$oSP1Q7fC0e3O=zaJrv02n9El||5E#p!X>P|)#sCYv}T)#=)IFK13pOV{vc7k zP5mYtB1%l=JtkzDN~td%!hO{=Ji8k1F7k3mvv+vQtWrMTnuO;*?DL|oRXuR*tBmI= zS!&Ltzweb;e)lQzmf&;be)!gJXPLZq@!s^L`&sw#W6@(VOW0fgp6sA<>K^qN}}eQ6Qvkd859o^Bv?B3d`<( zH7>aWXi3mzm>bYc>X!iM22>r?e0|&n#cw>w5MJB-Ba89RC0GdnI9+KnLKIS?HE`~m z0VXs$C3PErzza7Iq6&E-cgSu}!)m;J2HMsQQ$eHP`8h7x1Uhp;#NuwfJf7mF|M_4( z$Ev{1M@A0fYb!eSaQVu`&#&Qx!HP*lBWn5e%cjwx!y(^KbZ*0nh-iz^V?2gK>upA> zI<98mMoYX$v9wPgvuhPZ&|6s>w!QjT`*WhM@`p!hgmj~IxW3W0@z>VR5z(5hpDUkg z-|f%?)(1kPr1G6U$|As>(=`HvGLJtphxaDRYcR|*ND(OwVuPkjrcx|)px@P z$&6Fgop$r&NzWXrX=ch2%OV@aoZe5JCEVXnKklYjhLl|B}fMTd{H}4$iD7sC)yF zYskM)NRBw{4-_w}rAgZS&z`_QN3uGEa!3>;34XgNu=YAjwPv#;AbK28XMiW$!wM|M zHO}vuO}?{kIL9!p900n)Zn8Te|2ZxWOQqU4n%^M851XxG4Oli9oq@+V?3?U_hV!_l z=f!Ra0z+?YIuI(^d!|n)^v^;;l4_AD(AhRatqP*ol#$ z_{p?JE^b;u0b1{+H_`S*Fs=-nC75%tFX7&VrfVnA^N1_JLp_;Cs`z^kI};zPj*#(T z-83&IByDtYn7IOKY`~R<2?$w!vdvZwvd#(}U*U(;Nb+HwK|$=cMZS_e(|j zFjb>^=uXALuhe=+mf$%$W19BoFL+5W2np}=RZhbqr=x1F9pZ$S8 zlJg9XcAN@%nG#^+`LPZ{eeC$MD^+!NjsZHw$H%7`$pGPH%s(xy9gblujOO!gER zi|uw^^MB>1G#!ejUpUV(&UHsM0Cvf|Q%qP^&82xFS?Y106rUA%c~jDv@NPe*UB*zk z@5-y3pYngLkn&M9j?x~iWuK)sRr-llx}ncW}K6RzLH z+3wq=sguo!{>-oW&6W5-Dm|?Ps@cgego9##tsmamLYZPNJ8T|o+H7QOn$AEBhH}!fmi zK+?~Xgb6f)@DVbWY4c70Qdmv2lt6zCnV}@Tq?eM$XC2FNqA7onp24^)sKkxNW%p%g zxq;W50RQYRu_y*J#gXc|fFAQ9FzV+}=R8JYEE9){Aj99oo1FR!MY!|-(&v=vCJZxn zVM?w*j$lW;n4`y%%Kj^iC_zp-p6SAH8Ec{OL~gJ%hUK2eBY@a^k7$%;p*>d7Rt@Zl zdl({DB0(2H{k>cMXM`i|0WSS@fQ>}~8q@o&A=+DVQQ?;~dOr6OOL&LnALZsXULdAC zDjvC&!_+jF%4PBXLygtyO4xi7o1Sz55)5;XL-EF}BcFGW*r@Shq{9n1TKf+h z$)j-*a_LlE{j-RE3)(}8$auF>_L~OBS3*N>Yu~oFDsB6>U}!*rPnsrN)rP~ag_ZZ0 z9D?z=x;ao%#quB4_D8RV^Mn7^B46s^oO(I2nE4SE2}Njv{9A#x2I1VqzEM19);_dJ zwtj1CQah6A%4Yvd-J_wt%o}C&1GY@F4wIkuGet_HUF~(o<02_s7N#+0PznK2WMLvr z_ds@oo#X^ilBrI%VXh*EbKw5)ftSn>Js@&EphcYnm%++oUc>%Iu{O|q%J~GZ94)4i zSlS~U0GY5Cdhvx?!#7AtNwK-C08N5Ko*7+`X_th_SvvIn^I<8YuhQHsU2Fxu2Rl4< zTrYRy-_!)3xVxoDX7zG~t)8~0FqjV*aZoSgmui(YozY`Jy5*4FRB4=WJ7uh*AS41Xr z{tBW6q4C@xs)%7R({ZvHvZ)%4{4_y22SQp?is3pDb7L65uHa|gHsG4dPlGQ1Zmw$l zwkcS#40{2J@DLHr*-nA z2(_1ykscl9Tf%a+_qIC~SzNQz4zES88k8PcTwDE+7Nb9yXwv??sS=k`%d2qkGnJ}n zRVse_b%D}vw+s5kj1A9avvu)ATdjHEuz@u7l(*E zEZnSocy&O4%G$vYuDw-$HbZcxX+Xg%N9vS`uEUUZjUG56qVoT+_tjBRy=}V|B_IMy z3P`JT*AN2Its+RbNC^lG9Ri9BAl)DWBGMr_Gz{Gx(%s#0o-ux}zVG*a=bV4fIS3-@INKXipIY z1jhDGr!ZP+9Kdv+-HvA?CG=Rd%7AEK(KWuFgf zJnTk7zh4MX4wcCOu?8ANp*tM{EYJ2|?4@kV^L#hVewf{9Re2- zu)5xu%>!RLcEk>8vM!x#^6y46I^HX;`K)IoS6>6D;1zt`xhh+&{Y7fEaR(8AX1nWXOo9!I;vkdsf`AO}p9vGlnn*C6qyJR)L zRnGBTE{?Z*m$)KWV7;Wy1yL=AjKw78vq^DO{H{6pP6r8@&7GXedF0~7+36c>vyW&&V(uo-4B28 zlzk6$l>vYcKUptVtUR2?ECrL!+tgU|W*~UYMA5Kg$zS~r5nO6yQ%z`c?s)PI&b19% z1j+d1@!m=+C?FU>8-Z&WoubCy|AQ~3klX3uM-yx-y%J733@|}Gq`{vs_F3;|dHLv9 zb5d2{LpGO@Q^}q%pJ&k60=!gr7*`HZaULKj$;}`hKtJCZeg?=QZr8)zUd4dOA-ZW4 zgcx%0RWzrmN_JQDD?1f5R0af1+t;TV#u))ei`)`L>~xZab(qOyd?%{~0oDOiZ!Uwz z5)P3Va@Kkeu%YtV%)Vpm_^c5B0PJTR3DBNQ-Fk!isjM5IROZn#cZ8STzkh$0SqKD6g-R=ZZ;-t_KVaPl#ae8f{fKGNbK8TC zz>JFQSRN}&EVp&|tKy|#N%CMYIJaAKrN--6;`eP}qnR{o!++`JIbQByHC*nHgHceu ziSRcwQ1N4HY!a2K6KUvbG=ND`Y*>|WVo6#0P1v+DseqO;hc&BDZJ#=r6gATy&u9C2 z44A)riY!Jo5#CvKYwr$N0Mj=XL;s|j*z%zp#1o3@@RJ_d+D}bQCAMP0V)f1P&cGKt z2MVqbazQ5|10&#;FM81?Sxjbit<>ucmqggrj2wO>*$FN*mzS^Xf-UHHf1Z z@V%N8dF666mj0ODpowFhs6+L%r)lOh<^o0mm@*#028ILE61@PRt_N7yLs71}fv(YZ zJ-(t8@R6hfos{+?YJQ6Bjo@WsWrIMu?m&u1)N9W73e*~#lCoDcL<^#-cj6a1-i52} z&K`SnT?jmQ@HY{i$rh)Tn^Ng`T^{iLJ480Feg~eE4v#+tkr#Q27|dVMNbi5WWpaH zx>Csm?7j1b4wBXk~P#pqnM27~pcPeB7af#vhmu|ljS{uCIL$q61qWd|hojYwp>K1iQ^ zzmm|q{}g0Pa89%$FH+&)Bqj^|E|@LCCeK0X3YgM1=VCKIv+yFI9x!QPEzQ+)9?Mcv z{?+kR(!_w4i(VB(=vHhYNaZIER)<6VFZlC6{N z(Ze8db8|NQOV{4q#(_Tue5R!k|B3EsZD^HIE5THR5GwhagbKY;RH1I)sG7D(Y##go z$+)1WP5D^ALBhB`-@}hQ4y2pr9F9}#zH69Ut+O-PSYAmD9sJ%8<)YbX37xArTgsMd z9j_(e)5)i=J8mJ7`~=ryw1YxAC5x~d4V+sPo)yZ&)(>}<(Cj#92Lqj zvSk3FS}PAF&I0^W2_3poQlJtg9NU0YEap**_jtosdjCvCzPVd^Q>-fxpor3|OzhzP zo=uyLB05>pp}q=Z1`!G&1s(jY>YSes++2gWnCKoAe)wGq5?-l9KqT-m(fooJ8cBxB z>@v1i&*xa&*|beX4X%q0QFSxh*j657#1c8fj}|2ux%eMZjRj7?9SgRmXXG328U`Ej z*5J$W?beI6;_x}3ZJs_-p|{B84Hmd+-)&ODU6)!O5X@8;e;r1tZBKS3LAT{5p0{!n z86g%0WURoXlN;j4Ll@^urWCcvyFsPfhM#}+Q)vi8_UV<Hnr>V8yR$$!@)V7?nBnjRIga_W!_W(>F%r_-s?GCMt`*P6n?;qqMBj)j3=a zf@V5(U}jqBhP3ZV$9s3OZ5ai;zYQL%JY;2UK zaOYx8kllP#ug$t|QOaX^x1hj5P zbCD8?`^$8d#h?(W*|wZ}7urxlRfrlC7dzOMF++s8>j!nNeYC0Y7iohGBbecf1M0%G z0BFB7m0cGafM}lI4TkhkS)l($+z^Q}%FI3z#zkOW_2!)gTis~p+q>qzK2c+Q9@G-V z{x0fWviI<&@cSfV>+juf zd3c&&=MUOOpzYP*m93TX$B9aU_gnWy!7ZGe*6i?+c^HtWGqJ=mjcBtvy*I-pkwQtz zZO&>i3l~Ep^uD<2f-|HKy2un<_~UAO-You|IVIEA9XBctdd zxK4UXcxQPJG!EevRcoP}-IY)=v2Mbboj5}@v1EPO($Bxc&&RLrs!Mi#mD_TR=xHpB zLcycU=7Au1l{vo%^y6HArH727G>m?4b@SduqFM3zJo2{R(v#M_L~1cHydLu1`z8TChlIWI z))tBI0`zv{0pN#PWkna_I-Sr5pAjT)-$5a;D&R`JUB#B~_`Z%U-5!2tEcpJgWWmns zMiwSTW5J}K74IWo52txC->;V6%Zw)+$(5dbs7+pX{=xr1Aa9u-P5_NlfmRCF?67K%IYzTsZX8}#LYPq_9l~=Zv|&{)FcYdJn^ItR z-@t=B%tSEY$0a&nG;ldm=`m5>i5ui;PdzD=P&wO;d%L6lJ!UuaMGpfHi>m&RD&zgfsRwR*e+Daxkl_rn=T z|J`xeym@a60U>|MVohR{ka{CvGQc|o7-JY(+Y%u5+ zr@Z%19;oshq`l$NT?WFaNRXx#b++SpiO?5<6Iv_cJRfb+#vRx9wlU%DWlDQ}FLF22 z*}Wd0eAXhIu4%!9r$5La0-RC(ZC1zaS=|e%0(|WC6t!qx>rYE8PSi-w=LqKcb_{U( z>_8Z_lTfDTySaKPr}AV;dKk=5j23b&V-q_12Pf14E*Nyhhxf+v*Wk6M3-yvkm7s6(R~N@v{|L40843 zy4C?FN4!UV&^L7p61*DP`6eEKftLwUEmuo!CQx|jt%m{RIZ8B0Bm{lxs6;s42ed)a z^bOle_hB5cMBq&Wl>sLM(H7C*KWeFj{l_XQhTWeY?T7K{->Hos%v3LE!xwVwVFCOu zg$vdz1Po1Auf%%Li{5QJzf<_*1!S@9x&saLC2PKJjh8No0T~cEIE|DU@JR@`6;Aa# z^uVKnee3xp_)@=LY7T9s>nx`?YX1FE(8MwZdL6oN(Ln zh?rl9VN;2tvX^L&=wj9BY1nM_XDq&4KCzxFISCvjvUA2pMjI?|X@%0m`d%j9%Siit z9dR1Ovc~=WfewQ@dN(@wA4yLOz5A*QMW>=H6JPOTJ;@IAV)gMO43xWLUaTk#&?{{F zRuy}y25=37abN4nwfW|PRkKcK8qIj3ZAd%b#(n_Lc$Ae`0yl;;Wk;36#yA~aq7o4U z(O3W}4>yG)Z=Z%$g%Q?6EO#tNZ@){F0_dn*zQn!|(J1V#mU`0BPC5NAk=$%CSsw-& zehRJLy5e4`4>h*9hqWMvay5YH#q=pI)*%pCw&E*7^h8a-2y}zjI81~~CdZ5Y4kLa~ zI;BPnj(|+9j>(UvBRkJRSK+i}T z1Lg}x3fJA>HegWDcG+r}96`}2x<{6Ao*s8czLNmvoYLVa9a6dTCG+rr+|>T5L3-ES zhx=B%RHhmnhKSu=KfnY zSY*Tp0{8&qKphd*vjvaKSLFnuWI(y)oqL7B8=)4&xquXK5#(==CoJrjx^_CIu@2|@ zLKf8P{hswQ&x2N1>elP+UyKsJ8emD}EX#&!bB*&~gF6?@R()_d_z$osc^xBz@;{RSVs*tYUp6?Ze|6E9BF)Sr;~Cuk<_lNjoErOFca za#AX7z;^;2H|&|L1A6R%vPdo(WgfTiYQ{_Q@@l zXQ_qF&NTh;Pwho~ezH&Pv;D%qiVR-#Fe!s^1i@(hb5^zC{)YR|HQWUS5+WCL?KLKi zqA0?=9wNNpK51esQ<#$|+V$yu;n3^Tus^A%fS#(0nvVva_ouL+bKNHZyR#id!Ed_N z@eL`l9A!ScC5E|i{!1w4#WVI^2gzvW8BHN+r&1ssSxbjVj@0_MlcBzTIZ;_bT)<|4 zh*BcPl7y|PHRNpAU%~ZD=q{pIJABmpFRj@6_Dv@vLcP&SFr;+AdzdvEiR&>asSO|W zfc3fAu91ulvYWZ1t6YdpTCi5CCF{ML`+aP|Q(F3(*iruF8KHDbcxHTMC;V%i zrYdvvShe@UhY5yu-+@d=mZ#kA3G-H*PoSGTL9b9ZuMupi953OC|?Dkhn^=}GFLWlI>kqTgBWP+ao zT|_C+OVVNd)T9m7#s=}=xF^ROM{Wgk)DI?P(Oxxgfgd1gd-WQi zw%HzI)AgjCsheE@^cPp?^%DHg;!W6k4;LLrEs8PrieL7(sHd(tuYdeNsFz>c`zBcG zSV4$KkdGn*h!Urc*BjcF30H^$$OWJOBTPdH((GhZGUg$!#H=rD{7P?jhjp=3C_NN| z++PiB3;5=pYtQu=*~T&a&HBCs7g~%CXi|45bm~c8^*Ung`c2P>j^{4lLPvj zm!+kyj5`u6;xWi;5Qz?q$~U3-U*psF(EWlBIO1!19E|nin=kbt29pLa@ZO7)FDJJb z7IHooc04janG2T?V$m{J-&SIAs%dZ}k4Tx~Ycyz$$D>oSR}odGV;?h`g!s~k#^z$| zQQ4wZlbq$cfYHu!6vVPQl>&Ph{h>u_!mp-$25Par-2RL9wSGp?lCefQ1fjiVmxa+(>Dh}E;BT$316 z>Mqr{Q{TMW$)wvuObN5uCSw1C)oMO=?KaQ#sQlS$@f3~|(X4K2Dnjj|$Zp3_y~JV+ zT0+U%@7_x$*d!(KeW5Um*VbCNECEf$h0zm?KEFDiAxE>YbQOn_%AB@P2)^shq#LI9 zpS;!&!1dl0`i#?p-3{nf!oVIo-@{ckGl_)Z*JHHOJ)R|eH&fdsdEjQ6#isiXj>d0@f_zNbDU6V0vbFsX3Ed6gNN&d>qHo|u6$60@|T45ev*m4Lx{|$$I zy4DxP^66^Y%ileKpDzx0u|1MsU;b{@Jqq(6*?IJO@`=UoBR|*gj|jN-)n8x!rUBmJ zDH&A0yAk&_>u*6|U(}%4pAtSKs8dFsZnx*-Z~u0>Bs)&n{}THl-@ubfMkL^fivQKu zqQ8F)B?Il8zqqH%v`XR_U)XfS(G>cB)<^$*`(@h-*Dn?G?~{Ii4@nO$R;Q2rKJuI6 zB;En+&VcgoHr((3clXK_pO&bNk#8Bm0U)EIqC%x~c4&BCrxLE|I2W$c75W}*2`!*g zOY*J9Zn-ZQh#p$u<1Rb$e*XUcWjBhi0KsxF7y~Q?(h_%QA{m}3knmVC&fYi0lbulH zUrL!II$IFF2v$iAbj=DJJPa?iKB7Kpb;t(et??)*E+oI|jqLX{Y>=GRg{z|cJlDw* zJYHiv-k6$2%_=w7O)mHIQ+$2hjiEd-x6>`j;bN;qu~_^QAX6@5H*O=6mXUeTUm9@7oN~azpVgfQnUN;zRC=G+_@oq3kU~2_qgXe%G zE&|YJ!!)HU+2w}dcVGu%MPy!T3UK_;t${Bh65Y@Fn&w~}9jtr3^i`bKotJtloE_AQ zE#txP@t(rqsHl6u-JHQ`KBN>iG;DU$HL8izY@ltn!2S4O!)m*_u?1K%$QeyqZT~~E z*og#HQ+<6;IJkikHO#hyk3N#k9fAnr{(ijP2-NzYn1uDVZ9pHU%y>(`ou(%cd*%$O zwQyXBH(5q^&&2y%`^6soT>zjh!W}X(1oxnlM1<%0B@352V_UC6x^`@N_Sw& zCaOC|`g&Tz8Aw?KwO3@BOY8d#=;;<8YG|7p?jy0R8*r`5#lubRSj5MjuIOAm0M_D4 zR>vraqfNG1mjWkq`6~P41Yvx71#T`vhz}rMPe&r~j_LSgoftKwe-L4Z`Y>CeF*}KPOQ+*-1DLsRrh>~nJdt@e zV3wrNZdv)~!uOu=@-u^Rd)%NtKpx$Nvak(ox`9wAoyxO)jr8Z=zBWr7qHAjc1IrdD zZAn=O5_I4`Q$0~MjL!?D2w1euwNE#nZ)Jo+kWO}FqZH8#v0qg?0)()I@&q-&x?+%l z#o;4-vM*ilu0UpvKJM*Nn-U4RsBNzDMEunp7!jy9Y4RF}yb0G6=N{!Se!4iI6ZlATpGKeoa;RuX=y)N^C z*YJsv*~-SXwI@=?>#6i}2H`IngY4nQ3NaKMJqBddEfNgcnHGYw5sYm3-$1Leez!Sc zVX*;}yV`S`Uu*@D{u>3*g)dz%TbTv^mQVoW1Y+BEDnUG+3J@Vq-MH$IOYS&}>j?52 z+Yji+?B-KVN^Bg%4$r(3nYE2};XfDYFf3$0K8cQ~x5D`#0{o3(#l*6LmvFm<{mWPc z!qs-S&V6O;JZAUzn2N`!#;%x5gDAlcprt0xSqFlo_N;S2m(8oiNzAE8(H(FBPGarw0ISx+CiTIR&#@br6#JSsp$jg-9#}GZ4wzMLbkm7 zvb8h-!ku}_`DthBm^?iJmutT1764?L3Blop6f$AzF zuA)x7gk<7?XB=8L9Jk_3cNr$2#}7S-?$dAEIm4l!+QoV%#3?9T<~@-5TL1&a-PD?D zS~Fts)_P^ek4Fi+s%Y+W{k9>{IhVeNrs@%eOvsM4Ov%$$k}LA~^8L?_BjQd@R9-Ji zX+D@9yiktw(6jMNcnT+nx^m&DA(3&u*JmmN&tFs z^0TahG_Kl=XBCJ5MFK237r1WV&F4F2cgJJ=C>DUtecOc%z}69%xZ?IBYQQSmNg}%d zN5si5j&I3pXFsY`^iDyNW>^G!(|Dj=GlwLyM86)cvjv`3q0?(#EP~Iu@KR5ze>8MR zNo3vQP?}fptOX3tlq4)Z-i`ZJLQz~9&+ZbTU{gb8l=hB-sN>mXEnGsc?Z7(!J}4SILLMy?z*Nlpvu3iA6^@h)@ejrQ^dunvt?1 zmifbX6GXVE;=I@_kdNr7WSDXm?{J)Ki!XO_hZ3$^4prtV1^+fG-O%F(qQ~ZjanQvD zrZjTT1(4JQAyf%LJKHR?{N++|AXdwC*_?c6Fd4$4iZST09PpRo(O3J2OG#AlOY%qW zT;6pOJ;s8P=nsMnmYP&cD^9+&iDGEnRZDY{q*kpcvAyMK;sfXNMXf~O6kv7 zhXI(eB>DtHx5W|xk4WYae$zJ%eq+SB{z7%%h?&2G^^th}39vxd!dLmPK_bH_Y0#5D z2rv`fhnARhCRjl6Nac931wOKNTaQ1gj-oe2+fSN~od4`!aQX{J_EaCT9ytQLWqZn% zb;erSSvp{#`~f7R%h`#ZPk9U6Tl8X8&odLIS`siC+nxO(5AazjC*;V`$uy`Z9w6G&x4_&M)YaoivUGX7>7-#j1D?AuI|h>#*nZRA7RZT?vEvIM z;bOBbN;5jAmNhX{=$?kd6OK|GSq9pvA8-c=bZPlH%o zQ>PYthx!AMY{Q{8o^{7M1?h~M6!b@!z58v9f~MhSq^$`guJQHUZ|tBy-OLwjD>Uup zwW!Zfz)OE4q`QlQvr1ma%mJ;TzFjK?RnOyB7mPO$Cm+#o6(Jzp{*;J5(}2UtRsjOV zi_~!*4q=VUtlz1|oq7MLl5vstmLDtnagW~PNh0?3l^_Rf#>GkJ#-CP}(@xRg=mAV1*8nI?vYpK%xFIzh+ z0Lkm^K`3>&fIA+c;lLYXx_~`X{dU-jId${jOGp1w8VrW>|z`9GZ}N?3(`YN{ptcb z?@FIu+7Pp@A~L645{>PK7=jVs-yPH$$-B(DhK2%y`oY{rgy~Lzg?p~(wjJ-X-HfOU zco-B6Q+|)@k;aEtFxWbr<_ewE6 zyOl#|A}UV;f_0uN&$Jlwy|#JMcYO0J%Z=;nH@vU==VzfMm|bbCMFfy4N?nwWHhmYa zj7^$Om37PEsLBiAVtV56+pgRAR-_Gax}{8C_S{e47cUoPST1EBsaG!gLs=ohdu6rH z4s6Q{%?N$XVx@ct@t*fD$mA&;B@)a%&m=INu*E50XL=RjMa9{cmE(PE)EeP8(5}rR6pSqS!GWGWcQYCa(!-u;$0!tku^? zG%-IA(w}*2)X2(F7dkS=E+5!7K_?Y1JsPwm)xyeAeW}%q)w3k(d zkm#Sk>qjD7rB0V7U7+F^TovfN`u@5K)X)_SWB8QK&c`d4yzWt4l9Ae^PcVl8=R!g1oc((5VYbga>tJCjOpp>Tpyy{{7+}>4@ldXv*7-^1sdsq_<`1`o5IRp&|G+|e z`+JR0T|8FccTQJM_8k^ZM0=&zv@=P9#k5~xOscS4XV7`o`lbNeL!2tkZKowsb)r$U z7hB|=$yuTK5JUgB7HmIoPp*5)upg>}O6Cu}AK`DkAJLzBKUOiQy~nfvPVx5-llO11 z=iWN+77Vriv!mAFto2H{4&S=@Ru|`fon%yQek$|e`@~!gf=cAj>|w2@j{iyY-Tpd3+bESYLCg1rZYd4tE8U9m zYUomAPAJ#LXBlAnim`Ds{p|JA@YPmH+GeJ35irkrVZx4M+}gIn-Bdd@N|X28RN67g zl3B~^`XVWE?-!w@pR{NuuxZ%IAP3M#_Xo`fLDGD$h{(@tv+VvmnokILP(N$I{9hcD zq}@oHH7`HqzgfdKyA&_V}*w~HZD9! zeIQ+)_e1N7RWOg@S!@yo^zimch3#8UwA3y4E6E_L;TPIT;vedCE87g4|3rhvZPeu1 zP8>o2-HYp1d%(lM;Ox%FxFwyMqIx2(F39zib>7{@w0KGN==oNNS^>;FI?-6v-0iT@ z^2nlJ&yNA0khQiI`q_x08KWVIiS9;HNO-Wta#Hrc`NPh2yd%0hf3(ADrK+d!@57eK zgyT1_;o)>-nftK4p zI${a-7|!V+BE&I-f$hk4g1(?AjY9u0pP=*p6a9fN(ZwD;8lvGN7H4zWsV}B&z zb}OK8BMF)H@wN=*m;i@Q@eTr$Vwv{fXNkW`Mpvs=vOfWx3CMM&%=ERUmqXhS3LQae zFW(>DMQ0zRVkIj+QK=2XPM95db~$by6w7-R#*GK+7iJSqS~w z^pZIcp68b6kVFG=%11BY;0)B8MQPi2wqkbj^~6Edcb|6m?T#ls@q)i;NoBGUjnlj` zq|FcD`eiDl9`h8Y9A#M_*Y>UH!0*E?@;<``f7y~s=kU==*K&;X>GDQiiTvEy74iz8 z9HvKV5Aku-X1GWekmJW&wJlp1)d4D3o^XZ#=hKF zes>t!h5sNt;>{>~s@vqwdp~EnkulHM6zhZcDhH>Ad>5r<`L5j$qa7CJb4?AaXLPb< z6kZGlKRK{&z47IPBd^A^O@6e~UJ$Yr`S|7Lro9hAIC=d?`r>BXlQ)4i@6pEZpB_>} zKWC|Rvi%EhopvFmikrp;efU>3Zq}wuBS@_{pZcs93!C=P;P1#vVUsIedlQKA88lu1 zl8-INh89J`0nfudL`d);1Sd$iR(vw6c%0q30tvw8qz`11Gh>@Z>ugm;TBWKObnFTRYro8vjzC$g#+$Loea;TQf7_+_{{lsBJ^i?As$ zZkJn(&KeDnrEzrtK!N5OTArly_)3!&WiLZsO459GMwDmorPW@{Kpm0)XI$iw(vf+BYp^v8E*U#GO`FGtTK2FDU2fzpeL=qjRAas>utErx*;L^<+TWMlZ zFV=Tk^9CuCQwf63MSk?|v%!*bO;~^6x5hQ)17u%|*N%+GQZqpSmGOMW5-l_lglG)N zJ(%pE(iF7>y>wVY@pt=JC1GDx-l-ec9dYRxAc91GDI2r4|DI0Kz1W@H9?1G5odP9j zKl_$JLn}!#XlgyIL}N6k>kHVpsci+IF}RKSmUHIu-Q=Z0YH8LW_(ujzQ)v^ATw)YaViTpz`pSZfFmf{(enQb8S@JNGP_YLJ_lwuKoXi8{~wct7Q~gNMeW|#Q&Y{W zIXW4V^i7?g%b>XM|A*U6NJ?@7a2`rwNJ>26a&1(@VJwnVCae(%7#dyRF7)o)zq1r( zFhwg2U%km;F~X@py7e_we0fsglEeidxaHdfwKt`FSn;$~e>&XKgzaM`e!x6`B+N@9 zJQcz3Mdl^NsyWvhZ>oX-3>F&1?NQzQkC93=wRgV+ajUb4Fml(LjI!i#Zaac)IOMHU zH>P!hq?LX~>0>W#C`NQA2@drj&Cq9+cO5oRzc zF>doAUBtcJbsTfGCi&QXA2fTX%jGK)sF}X`g zl9l+Y=v=^3&!I<$1@qZjy<^mnr63HNK6&FlLv8~zo8Rj_OytpBG1Fve20vN|>@IQ@ z&H8gO6=Dma4WyA$rqDiFek~Kir1Kf&Ajm}d<;c8Tx~*jhk}hPt7$m2JEG)CcHk%ed z2~VA|mqvIpPH^^0e9QvQxaQjhF;UMBs_moDF9=(%)mojOO5>Xzh{!j~b%u2MnsZwp z(!DwVK^5JiykdQsntF5zmqD~_LE|Yr3R?R~>)rc>U?hcj?-rmC&@wu}CZtP<6a@YLd^qffMH5v0Zm(1$IUtPA}RNXyBB&Enmo#gcU z$S=O~9w6i>Xj$8{|E2`5V}dupY?b;#{x_VwD+72zNesDyznMwTT2a6O*0SS$efta0 z{$lptg#da|`AYBV-!Jnq_a>ksb79`gzZ9Flzx|2kBf=%DnzQ`xm-+vv|HHrc|LoQO zC{BdrbeS39bK)yDpGJ4Cl4UUGMeOuG>iwq!0v6yq=p`gOfbWb1Ua99Tz>YV2GW5;t znfkYv;VCI8(EYiTP=ye%x;cF&d?HFyCO)E?u97+ne2ttl^=ePQC{ZeQdzrH+&XLo1 zB_oNR8Wch)u(z>3%PbSu2s9&PK8n8-_r;6~T?)D0|HCVzg6<&17YyuzPy_59l+=Q+ zgJdOpfL3eJ*I{*tQuzEZc@>znxZ*=WXkYNf*~G=39LpDPsn>pmOt5|sIVqbc>jV!y}&r2AM%~Bx~K))&?;piUC2&;Uy)!p%L-%@$^B17#af%-`618x+BLM z?iaE2#A1~oy4JB{6kk>H{SZ8L;- z?>O)PDvl8u@8%uom|5n{u#jfLILPeEA3P|2PwaQ=>j&(4fnMS?Z-D|rAK{srr78rB zY9AQnQbFVelDcjM!H$MKDbhB}>1i=k$Vf(HQZCYJ8M{MdpXj z;E{^(k4|KEn|sme{|)@R=3_u6>zr$JhjqG>cLuB1L5K%C+qR0gbhomFL?liGy6h8Tw~`+&)iH@#?{-#uNWwSk3NgK_{wU z1Q@Yal9HO*47{B*TU%S(z^50*4A6=6{>B8$#bKi`ERPG2pGeyDrkm%O+sPUN%=DuWR|BzfKvW$?u!*6-QO?vYr;+_;bLpIkT6LjZ;z8oQMph9{G;3|R6H*}APA8u;>Ad`F&8BwucAdfR1)3NIWO)a@w7pFmYAkZ#3#xFQY%#cd&`BS9&14uP6LPMl{hMXb0MEP>8y1wMV z*y8lP1sBZait&p`^fv1ZumcaI{!1LKlDa&QRF5Ch;G9lloa!1muwLtAj+pEQch*>XTI723?Q zUrzB>&z&`AtYhHKCA#Y0^%j^iqn+a1H$AA4af=Cvd(J=y=9Rb>`@P&@v{;$Kf{_dV zdi}7lkYY6ZBc$qu!%s> ztHW^Oz#AIJ`6*voXd=_kEY*=rbXK(N~r9?XtDs7M?PXIhvew z9OOmRZ5p?u;%7CIJGa%Z6cF5vJKSR#<9hggjA@$LV>JHLD+{x-KWE4sP~svMM8~Y4Za?@+9f zV(saZFl>IYKnu+UqJvwUvlc>-ZK#jBE>VCIg&xyD6zsEk34GCeiog{8TG>a*7g5-l z>TEZL%i~cZ6b!m#(bliCMpySL-Z=+rIYBUaaF~Dix5(_Nj>N_N+NGKBz_$tIxZPuX zNz7H}j#~JtXaw4lPOii3$o9@}HCpu+SPVE6lfh7oYzu>Hl4eaO{R<;fVf4xIccFXO zitb<`30UC46C>v`jg`hZN@ioGzE8-oa&HTz0KAPCw&W4&hBIfT#h%;Q4xpsexn`L# z{%|(=c#5cXy67owi?393N7T<|Oxb^GHgo>x{gIDw_f7Pb=%CN}(;@Q{nuge(*Z}H_-(!x|8cfqB7XFsw)U&KcI!ti z`TG)!DAR(&%4B@~8hz2tO|x7^ z`D3F41=|zk;U|&`dw(R)O}L$UM*YnYc!*|;pT2#w zKx&7{TAmd{)6YaLiDT3{sAwLEU2qWl)A1#HG}6f2O`WdJzE;bnQeg4v^^v6DV<7|g zh^dRUi}eqMOvE+Z29CB8sn;CO3tK{N+bH1^rSH_?{OZ1E>ms!vl4!pB0ZZs@FjfUQ>RqRr-4rx=QVWO?RNt}!4m zLN-zMK2GaMt<>F0F4TJEMijeZaVDdzN>CGNEKW>khww(iQ!NrY@>tF_NC<5t4K>yjX_UP-EuD+dFa(jT`Ig`Lou4lcWHGp(?! zqgS)Y00d-gH|h@0i!PCDU@biwtU9MXIaqKBLhf*mOR15wpySh1W@pxmipqW#%Vywf zK31X(@;&bCTvy#ai3PP-XD+%R#c}D!Xtt^87~ZqpULzp8tEu!Za{eTg=r|vpZ@ZvS z_aK7%JHj3?m&mXNTlq$nv4S$1%#?E+Gp$s89X zeu(BbIlM4;tBTV^sOsSM1M&4{gjipSG=9}Gl>)=<%}p7+%GbH-@6{ASl@O_RGOV%8|GoF}U&BwsU)}EsG zZ!We^(4EcZ+lJepIr%PH$q-89J%?(-ROtwlLl^%Oa2h)qoFg`=S5OcaP9kOQ1+8#q zoI6>RiUL|+Bk|{Bv@#aXDPCQ?pO_ukIA{s>=yq4GCQ8huWQu%FsdJ%AvL?8{Q>p9B z!#Hfw)8%Yc{Z2B-IU-HQhdtF$GouC1!rcp-Z~Syg(LH2$cURLF(oCrJIv5Exw%sod z+!2RD;D+8w4eZo_jR8q&i|187{KT1FnR7Ei;4`CPVq%Ki>O2U#m;oWvmf5JhI;A#7 zNYN8gz<7SP;ob_``E&WL%p6C05MXElI#-8T&>Ec=Oyn^i`jA1MgM-p;J`Q&@4hac= z>Y;s$WsaIx2P9Dd$SQM7tPrf?UHSV7%!DIm#>BZef`F9Ba8P zS4SEQMlS+*##Icd0t2ZzqCaX`Vjuy9L^&A2q{CdXt1=^9hcEseG-X48ZdDvPOavs6 zL{?p#ZP);tc`Fe9$wecF?|_Ps{$R{jv9bbx%P)1dG18v&%`KMWb)&Z_s&BV%*o<3c z#H%WtzqWmv{+&%)Wsp3=Dq)P$*^PfbPjF|Q1Zhy3+0x!VWgb4a2yDz=PWQAq%aHl5 zAf10yz3 zjmXDoOfz=%)b6^rz9}f$f+n01E$uBW<2pBFT~zL;_X{bjD$3u6Ir37@nKi_g6KTw+ zHP=+f!zj-4Mhl4vH=on1GR#CrxY9II%W25n5v66I9__0m^Z3R0U3F!om?el29$P@Y z%wj!L&(7{TO34T1)EG#k2xl;(_hm5d(V%IRz3`RpNq?!X9v(rdc$%;1#`mht%*`Zp zRzz#g$iV3{q`%dux+T1->%3uA@U{j4sw5 z^JT4zIo6>A6XVu#ky4S~e1S==APIXizU2|^>Ij~NQU>;y{X&lA7F?!en?vptn>~#W zruaZX{!XmZqm0*^@ z&L?e{gSU%-{VF=icH9iwRhFAMr!7-`$@$0ePmqCqWaL@2^k|~$s;KbYV5wLS$;54n z19b}4X&l+n6Prdhx+jblkns~9V<~^qKu42~L-+o<$$hzK>$x1S%g!Sfjnl8{`u(&` z#-56iXg+yZ>GUF&ZI;jBxvq@}w5>4P%&@U|Nrj%Z=AG)-pTp+SW^G z-U(Uszf7AaBY`nSvaRPHxK;GJQRj+x<7VL=TQNke`k_}t17ET8PS#A|qF-Iw-%~hZ z*8MUux*L_y77;2N8L~pKaf9eM+D5FxAoDF}_RT0x!1uZ!LuvgZ7;Mf!>oE|gHBG$9tDw-Kuy!gq*G#x%zVGN${Gfm4==Iq zwb0Phlg{7-2?lxrby)0$MevwUy$B)$CYktw7%NYy=0oG;@nUii$ZtIcF~oDgY>lfQ z$F`WYDRlpS^Jz{j#4(?3ml?h(8oC-OfvP`Z{bEx%HdpEnDf$IZ`c>)#R_W=EWL!Fa z%OufL9Y714Ca5_<@$&Uia)g{7+4A&9*pXL6Z8_J|!2E7WY$HYXyzz@Byv7~JViV5D z=bazkl7wl-e)!$+O5?S6ewS;l2EdFoIcR&W4`#db`iR=rSB{=MAK@8fK)A>jG9TV{ zG!K|X5FZu>CJwh|jE;Ag=HF7@xehrx6>Hep2A!j53O={On^m0f zoK{%r^zIGhOp&1C_kLF|>Ot0m(Ya@G!QQln;MUlVSm3kFyC`-1)RS{UOL3bCj#zsn z7I;Pt8O{OE&PKa0i><7WX@^jpS8D8^y9^PPJ-te9n_@mEQtBc3oiPNvKE4r!Q4De- zMPrv>V`0QM#}baxDL`(?P#?hqPw~RQoxV}s(i|)=b(R`=hOJ$CYA{LU~drh34eQJr4jsF48xGcKFi~PWMg5x|N@TW>H+{=+|3b!{mgxl1lPcE}dpj#@?9R(ni`5th*B5we<6O!riZ|!x z9aV3)2zzmmm2BtttpPM>;+PA_)DXLn8;^AeZ`p-Q;e1S z^m>+9<;1=E2;3~F@`KSwx97Mt`;O-91JWKS0iL1@tB(>pS9NK)dQ~7H|Evuwndiec zp2UUS)Fmbu99>%)9KR}@D2Me9NR;@~240ywg7KeO&si)gjK; zB*W^dB(dHq`LTAIg4#;Qqb=P5lJjVl={?QH!X<(Cu~LFo8dxziJ-<^=WZ z_lE_M@LVCJDr2|>Q!tYct{vQh;04_rYC3HFGI@lg?KyL^D-?Jcc>9(@ry9$2`dd!t zJ-kWA9sh<735&wxSJh*QozBH0Mf(D4{OKsp+;lGBht&Dso#)W?GRx2zH~ec7V8t^6 zSH22n4qRN!K3a^PeNu`rpE}tsbS}-zuUH2-k$I*NsqXG>_++Wc77od9LaQL;?f@$k zm*V*F+*%+Cslw?Kwj4MC4?-;92nq^n?`U{4GG?i!i6!Y28|HO29Jp%sGcQx^o0%(# zaOsmw3Kfc%yitqA)C0Q2eh62- zYT)^n{Eoi|doN>E_H+tM5F^R%E_(*)LpEF%FHfaR7Z(86)qCB2X@Y@hb7%Qk{e{L@f`> ze?`R$^Xj!h+zm|Fp`Fo(wq}dfr5{X%_JWpsURrY{$Rb>)yfwPlTr)BPYYu9}3gXg? z#lp))JHZisY-=K=E zsyiQUvs0GI8U}Kd5k|8wBO>v9B4Fgj?K)jrUgAOSbDwxd)DryYY;Gy_-VRuxH7I`x z8UU4$T484PHU&i6*BO1m!ohHYMU^yB`VgS4VoqCI8+JPo+1|@+8f5KoZfiSjk(>8e zG=izqdET-@X`~h|w*8G1DGgx^xRt5J%2PKr%{JPRask-%?!gQvurG)(Ih-Y1z38(e z6U(HKQ7qoavPy^Z&$xP1rkDKI8DFVgwRzzTgmgTdNS$6}p)|6?o@5TmpVYYr+fP}8JUsb1L;KU>AXg2Kzxq@@=wADF zska=fg8c`*$2E; zzWH74w;t7LK7e8CMMIPGeP%q@&K>8bkH_PFtY?Td)m$!HcdPGyf2J?$nm)X^-OHrz zEHo>hDz%{Lvbd$i5jmL2$|4y;`Kh){4;8Wz&F~b#)$_)&qT|Zq6lx$2FV)e@> zg%#RR@v2RM3ia$(Vrvk~Evd6YqB$5d5?45LV#cMXd-E60Z%8b3S5bl5DBub|-Aq)H z*=L-A`|R{SzVC?Mx+js5QEg*fY0kU(S{|N8(Q5ko4g<~pyqV;O4ZCLC2Sbh**l&LI z`Era3$Ij%b+NcIMujdXaacZHcrxbT(r*MdB1Px3?TUjL_+~dk^l~=4HK&0 ztmQ;C1VQ|c1|MNe-_U+0jc6MJ0zTux0CO@%$lH(fx6+8Gwm;A{-|7HVv{+2~L`5he zAYT+WfeaA669c6=gtno&yu_A~xz#ZMY6y)Go)p`}5BA)ll38%J?4Tp;R9fL`2xJ8p zy@nMi8FtRonmsS&#rVv2Pko~?+%u4dcBi#(2#UM50cG;_ z1E@>_%F zSGyX2XEJ?%y+aG8ACWg!l$9r;#zSC1t6-hx0i)ty#dzh+!zEIO5%o>j7nO0cMx7*n z6njzyXIW3v$H1AF=k)g!o!$rW!sPE^<*{DuIv7YE)-?D2OeanAgn)NQ2Qu}DR!1pv z-9n*urQa7D!Tgz5>`1?8S=r&&6K`an<}$xnF@U=ln6&qIcHC z%i=j$)Mn{w7SqCqll8JyMyV6&%V;;f%=tOYnNpZs-E-?>_ck`a(dy3rHEXv;x*1F4 zwrYL#WSEQ!5D17s0_a$e`ZBJ98WsYHLFfPgDKrYe_`6x~#KY+9a<{*?6q(2jC%TCj zdVqpExEX2J?}( zXJoejpTyWPW!891qC@|{r50G3OeOaBqAOqi7t2z>QixPn9Xq$(t3PmDcYt3n&aHS1 z#sBLBn%inWIo>~U??|txi>5|}VVS=L@^A4pJw$UGU)m-22hOyQ?jGa$*$e&0|A^>c zjO(&6na(|=sQD8INT9oib;qEHfB*la{=Y9#MssV>!b156?%kx&6x|!>2Y9uvW-^-T z5BuJ<_s*-5kA)>j#E~G&82|alB2t)@T4*RfxNzJE>A)?1VLBr(@lyTjG$Xv27DPZb z7?b8)_fZeVuv|l%-f^wA9vv+$U~8ZE~Nj=hdJ1f)2 zV#-qke(ih)IV{177y!q%~0V{>a1O>OJI9>F?$G<>?VN>~ncf^zBqJUh-Jhi+DUg5m)ty5+;* zs(Lv2G;A5SAc;MBU+i|FAG_n`zA{8cQjkYE9IteBqhxvSVy$aA(|GH%(-toGGA`nt z=a~b-`3XAm^DQ}9vtk%rA4mH{a2NLBkXhvY{h8Z_F&itc%~ay$P^CdlJ5+&hcUSGMN`zJ zs|(LnCVaQzI(mrc_4vgv60K9romqgLGjukeFnpuZWKi`W1Ha!!I>9Jfp7L1@4#Rox z=LD4+oC4^W+s(;GEki@uP)bVYqpaDpFtsoK_(z-5+oyxKH`<7aS-d#}((VbdP^}Yw zu3YF=56jNww!tesJs#xotBn5qQrqPbgQlgnT?XcY5&Jc*e$Kv3yg6l6o^^+X^C^wx!adEL(z+?#n9i#m4@@nOS9FyBg z$V=$<1St8<;^yUEqh!RKdj+clY#2w@kCJ39o=4nTT>`8j=OL|P5+py6`dMY(Ml51Y zEL~+5<<>3jTE10Lyk$QD#e3pf?*VnHJ%6hXs8UadYYzmJphgNx5MNeSTrnl$ezIq- zB+7ZQt)y0q=GCTbjZiaqdGzA8n3e#ij2>Xr(*L0JOEohYR(< z$IFrLj#)_av$Oeb{hnD6fBkMHyLki(;S{fr5pvg5TBHk?ht$UO(242hba%7?Mhqjm za`*DG4@k@1zmrnCrcp_6k0(5qti5+#Cm|X6#zipFbcibhZ%2Wy(c?w5ztPQ>qXyO);ory?CI ztFvb-{0JJ{S%|T5BgK9NP&CXZ@%dtG&x(fJo>)Jc?iyJ4xu3e}%u(M!fHgl>P&*v9 zxuY$b08-B2A1JiR9jVwx8}($(`H~ur_;~k8|Ay;KTIk!T$qf%vGo7Ibqn=HOhfv!; zqxqK$*1^Q~kLlCTq^D5TEy^pv+4}RC+2hp&cBR(q(b%2G;fkv}tf#LOKk}%i45~4g zxhPXhZ@Vkf<25cFQcbr4v}5N289vCm)QkyScg$Kq?DdpVczh81T>+;MauDQ9BR!teE%v8L6!BX@=8754dK3*R2~Fc{~iJd~@d zs?yTZl7+VhDnEd4#j)j>2XL>oClEdPU0o)&_MV~1_}+eRHXFLIu9E9v9(Vr73B#>! z-@;kc6Pjbrz!~(GnTzF@=O12rFZTEnvuRjZ@DS48ilS3x+z&?U#l|LH`V@mc+$CGX90mEpt+)yg;XffwV2j9NEWGxPdf4?X&8 zP&AN6T7k4iudtFgP{`4`Q#Ln8&dyBWM?eE4+68FdYmBZJp_)XkjVQGzCtUI1)zf&v zs<4~o_-i8f(RUbFg?-GHkM7k3<=X0#l-`rX#=!jrEMIaiSsFerQhU?LUbuU| zD{r9VffvB{xoS-6E>BPuD7`hXGjHADSe&}j-u%Yc+*9Wh%f9pJ#8Fts69%o?s`ZPc z$!6s9ruPKse^ri$SDx(G?v%e#?&a^{l*_rmJ9On--*r-?^LCM}pLh7wlP8wWgI3@O zVe?OW|BR);1zg?ROjePps`o!$^ZEuICq4~EVD`vKwSd1BW^QcIc43VVTR@MNi1ELv zr$4Su$>DmXLM3rADjT$b_1(!PhvjR*1ldsKCb&D{QTx%JYy1fn;R%m(Ni0i>g#~$> z=eIZ0naE6WK3JQ6E_f_Z$d?->*yU#Vqg?ndNkLELdTudD=*6o*qLXsQbAi2wzVK7z znfdTS^Jb-WYObedu33R4sIJuiiR6d#H?EfM6tmzbvT}9I77vJtGx3&ZIDLK?OG`+1 zN|;;ohSQAcE?bY`^oAgouiyd%ZEE6zG4Tgq@K!F$%C7P}@2G4Ty=W;!8wV~uvQh{5 zfp~ZsV)sIITs@6HZu8V7#<89^xYOKF4ajbPDOr)GBLI;3iey zqVX8d-)3rCn6!KxX#N%?No!W&>e%P9g8JL0GvNX#Fyl>cQF}_-qvvlp_6J+%dqusx zelUxm91Ln$aI4E#F!Y@u;KoJVVh)2z@apRb$G5o&>PcO!`oyg=J;%onLV^i1(4PIb z^gk3}CBZ)eathH0rih^67b}e}BizT%K_;vgIm@Y%Ftv_^vR+Soy@R+)@v;9VBk3@&OZh5rH>YVoA zf>J|gB{uW$_$U7Ry;80IB}|R6X<#X%Vy>@y=MqdJ#EN*?k`3xs8cn-LizC`zw4Uq=>=K zPYd>Zq)p^?nuKgx^2+PfyKAQHaguS+z=ulpY|_X1aG`VtZL0W zWCqHqA}{GAQg(|{)#D1*0&|m5U)lI#%QwHzEY(lj5hzK+8>ehj^shzs+6~D*z8mZZ zUGVu+&dcZf_di}a{>?I*Cy^_FYFNHV>G2F5oPlA0rcK)j93tp``VuxI=saY}HK%;n z{?8nOX&;FD*I|YC)gPwbPCe@a0KMhohUlafXiS+zGT(1DEwN;_4F-Q+C8N-zHEe0o zhkSoJI2dp@xMlqY5;|)l1>qNj_)JhVud zaHhX$iBQnJTZjbD&a@r`Z+w4KxlMO&ns)`H(wW{s}7W#y2y{&Q<;%wtFmb?Kfn zbwi&a@xqG9n?Jds5!4u?@L6cAB#>{-qPyZfH)#EzA=?%~V#{`F!tT!naD+DCm(A+KCS1B_zimmI`r^Lg{k_KiHzfr!44vN$NPN75>&Q}tMzg&C im<#+%LC+n5=bl^(uU)kwx!CTZFGV>uNU@Bu&;I}tjA>v1 diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 073766dc..ae1f4719 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -69,11 +69,11 @@ def run_pipeline_helper(): log_enabled=False) implemented_checks = get_registered_beman_standard_checks() + cnt_all_beman_standard_checks = len(beman_standard_check_config) + cnt_implemented_checks = len(implemented_checks) cnt_passed = 0 cnt_failed = 0 - cnt_skipped = len(beman_standard_check_config) - \ - len(implemented_checks) - cnt_all_beman_standard_checks = len(beman_standard_check_config) + cnt_skipped = cnt_all_beman_standard_checks - cnt_implemented_checks for check_name in checks_to_run: if not check_name in implemented_checks: continue @@ -83,27 +83,18 @@ def run_pipeline_helper(): else: cnt_failed += 1 - return cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks + return cnt_passed, cnt_failed, cnt_skipped, cnt_implemented_checks, cnt_all_beman_standard_checks log("beman-tidy pipeline started ...\n") - cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks = run_pipeline_helper() + cnt_passed, cnt_failed, cnt_skipped, cnt_implemented_checks, cnt_all_beman_standard_checks = run_pipeline_helper() log("\nbeman-tidy pipeline finished.\n") # Always print the summary. print(f"Summary: {green_color} {cnt_passed} checks PASSED{no_color}, {red_color}{cnt_failed} checks FAILED{no_color}, {gray_color}{cnt_skipped} skipped (NOT implemented).{no_color}") - sys.stdout.flush() - - # Show coverage. - print_coverage(cnt_passed, cnt_failed, cnt_skipped, - cnt_all_beman_standard_checks) - - -def print_coverage(cnt_passed, cnt_failed, cnt_skipped, cnt_all_beman_standard_checks): - """ - Print The Beman Standard coverage. - """ - coverage = round(cnt_passed / cnt_all_beman_standard_checks * 100, 2) - + # Always print the coverage. + coverage = round(cnt_passed / cnt_implemented_checks * 100, 2) print( - f"\n{yellow_color}Coverage: {coverage}% ({cnt_passed}/{cnt_all_beman_standard_checks} checks passed).{no_color}") + f"\n{yellow_color}Coverage: {coverage}% ({cnt_passed}/{cnt_implemented_checks} checks passed).{no_color}") + + sys.stdout.flush() From 3554fbd6370859fc0152882301bb6c49f548662f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 12 Jun 2025 00:17:17 +0300 Subject: [PATCH 170/371] beman-tidy: tweaks in docs --- tools/beman-tidy/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 461ab429..2dc4e796 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -48,17 +48,17 @@ Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). Coverage: 66.67% (2/3 checks passed). # verbose mode - no errors -$ ./beman-tidy ../../../exemplar --verbose +$ ./beman-tidy /path/to/exemplar --verbose beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... +Running check [RECOMMENDATION][README.TITLE] ... [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. check [RECOMMENDATION][README.TITLE] ... FAILED -Running check [RECOMMENDATION][README.BADGES] ... +Running check [RECOMMENDATION][README.BADGES] ... check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED @@ -69,16 +69,16 @@ Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). Coverage: 66.67% (2/3 checks passed). # verbose mode - with errors -$ ./beman-tidy ../../../exemplar --verbose +$ ./beman-tidy /path/to/exemplar --verbose beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... +Running check [RECOMMENDATION][README.TITLE] ... check [RECOMMENDATION][README.TITLE] ... PASSED -Running check [RECOMMENDATION][README.BADGES] ... +Running check [RECOMMENDATION][README.BADGES] ... check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED From 56e5fca1c4a733754d14d58994ba3c9c7ff3cf27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 12 Jun 2025 00:21:51 +0300 Subject: [PATCH 171/371] beman-tidy: CPP.NO_FLAG_FORKING should be REQUIREMENT --- tools/beman-tidy/.beman-standard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/.beman-standard.yml index a6095830..d7d34c4d 100644 --- a/tools/beman-tidy/.beman-standard.yml +++ b/tools/beman-tidy/.beman-standard.yml @@ -156,6 +156,6 @@ FILE.COPYRIGHT: CPP.NAMESPACE: - type: RECOMMENDATION CPP.NO_FLAG_FORKING: - - type: RECOMMENDATION + - type: REQUIREMENT CPP.EXTENSION_IDENTIFIERS: - type: RECOMMENDATION From 7c1de6a281514d4f11dfd8a389c6b5dc1b4f4de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 12 Jun 2025 00:27:06 +0300 Subject: [PATCH 172/371] Update CODEOWNERS: add explicit owners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d3be6f19..4db7c078 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @bemanproject/core-reviewers +* @ednolan @neatudarius @wusatosi @bemanproject/core-reviewers From 94692d7e20e635ef7a88d94e8e2bce8ff4b9ff3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 12 Jun 2025 00:47:37 +0300 Subject: [PATCH 173/371] beman-tidy: simplify dev docs --- tools/beman-tidy/docs/dev-guide.md | 64 ------------------------------ 1 file changed, 64 deletions(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 6405e3db..9342cf06 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -22,70 +22,6 @@ Limitations: ## Tree structure -```shell - $ tree . -. -├── beman-tidy # The beman-tidy tool entry point (Python script). -├── .beman-standard.yml # The Beman Standard configuration file. -├── __init__.py # Allows recursive Python packages imports. -├── README.md # Root README / docs. -├── Makefile # Makefile for the beman-tidy tool. -├── requirements.txt # Production requirements. -├── requirements-dev.txt # Development requirements. -├── lib # The library for the beman-tidy tool (e.g, checks, utils, etc.). -│   ├── __init__.py # Recursive Python packages imports -│   ├── checks # The checks for the beman-tidy tool. -│   │   ├── __init__.py -│   │   ├── base # Base classes for the checks - not to be used directly. -│   │   │   ├── __init__.py -│   │   │   ├── base_check.py # Base class for all checks. -│   │   │   ├── directory_base_check.py # Base class for directory checks. -│   │   │   └── file_base_check.py # Base class for file checks. -│   │   ├── beman_standard # The ACTUAL checks for the beman standard. -│   │   │   ├── __init__.py -│   │   │   ├── cmake.py # CMake related checks. -│   │   │   ├── cpp.py # C++ related checks. -│   │   │   ├── directory.py # Directory related checks. -│   │   │   ├── file.py # File related checks. -│   │   │   ├── general.py # General checks. -│   │   │   ├── license.py # License related checks. -│   │   │   ├── readme.py # README.md related checks. -│   │   │   ├── release.py # Release related checks. -│   │   │   └── toplevel.py # Top-level checks. -│   │   └── system # System related checks. -│   │   ├── __init__.py -│   │   ├── git.py # Git related checks (internal use only). -│   │   └── registry.py # Registry related checks (internal use only). -│   ├── pipeline.py # The pipeline for the beman-tidy tool. -│   └── utils # Utility functions for the beman-tidy tool. -│   ├── __init__.py -│   ├── git.py -│   ├── string.py -│   └── terminal.py -└── tests # The tests for the beman-tidy tool. - ├── __init__.py - ├── beman_standard - │   ├── __init__.py - │   └── readme # The tests for the README.md check. - │   ├── __init__.py - │   ├── conftest.py # The conftest for the pytest tests. - │   ├── data # The data for the tests (e.g., file, directory, etc.). - │   │   ├── invalid - │   │   │   ├── README.md - │   │   │   └── README.md.delete_me - │   │   └── valid - │   │   └── README.md - │   └── test_readme.py - ├── conftest.py - └── utils - ├── __init__.py - └── conftest.py - -24 directories, 62 files -``` - -Notes: - * `beman-tidy`: A Python script that is used to check and apply the Beman Standard to a repository. * `.beman-standard.yml`: Stable version of the standard; the tool does not fetch the latest unstable version of the standard. * `lib/`: The library for the beman-tidy tool (e.g, checks, utils, etc.). From 16b55edbb1f3f95d2339de7f0c9361d3e87180b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 13:14:21 +0300 Subject: [PATCH 174/371] beman-tidy: run the tool from any path --- .pre-commit-config.yaml | 9 +++++++++ tools/beman-tidy/beman-tidy | 4 +--- tools/beman-tidy/lib/utils/git.py | 7 ++++++- tools/beman-tidy/tests/utils/conftest.py | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..41efdcfa --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: + - repo: local + hooks: + - id: beman-tidy + name: Run beman-tidy on repo + entry: ./tools/beman-tidy/beman-tidy . + language: system + pass_filenames: false + always_run: true diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 4a6d869a..478f9aeb 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -6,7 +6,6 @@ import argparse from lib.utils.git import get_repo_info, load_beman_standard_config from lib.pipeline import run_checks_pipeline - def parse_args(): """ Parse the CLI arguments. @@ -35,8 +34,7 @@ def main(): """ args = parse_args() - beman_standard_check_config = load_beman_standard_config( - ".beman-standard.yml") + beman_standard_check_config = load_beman_standard_config() if not beman_standard_check_config or len(beman_standard_check_config) == 0: print("Failed to download the beman standard. STOP.") return diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 9811fe06..21dbff88 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -57,8 +57,13 @@ def get_repo_info(path): f"An error occurred while getting repository information. Check {path}.") sys.exit(1) +def get_beman_standard_config_path(): + """ + Get the path to the Beman Standard YAML configuration file. + """ + return os.path.join(os.path.dirname(__file__), "..", "..", ".beman-standard.yml") -def load_beman_standard_config(path): +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/tools/beman-tidy/tests/utils/conftest.py b/tools/beman-tidy/tests/utils/conftest.py index 9ff374e0..45cb4060 100644 --- a/tools/beman-tidy/tests/utils/conftest.py +++ b/tools/beman-tidy/tests/utils/conftest.py @@ -23,4 +23,4 @@ def mock_repo_info(): def mock_beman_standard_check_config(): """Parse the Beman Standard YAML file and return a dictionary of check configurations""" - return load_beman_standard_config(".beman-standard.yml") + return load_beman_standard_config() From 51aff3196ee40cf136c3fe7ea5af1bc17ab80e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 13:40:36 +0300 Subject: [PATCH 175/371] beman-tidy: the tool should propagate non-zero code on failure --- tools/beman-tidy/beman-tidy | 5 +++-- tools/beman-tidy/lib/pipeline.py | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 478f9aeb..3558b21c 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse +import sys from lib.utils.git import get_repo_info, load_beman_standard_config from lib.pipeline import run_checks_pipeline @@ -42,8 +43,8 @@ def main(): checks_to_run = [ check for check in beman_standard_check_config] if args.checks is None else args.checks - run_checks_pipeline(checks_to_run, args, beman_standard_check_config) - + failed_checks = run_checks_pipeline(checks_to_run, args, beman_standard_check_config) + sys.exit(failed_checks) if __name__ == "__main__": main() diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index ae1f4719..5dab18fa 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -29,6 +29,8 @@ def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): Run the checks pipeline for The Beman Standard. Read-only checks if args.fix_inplace is False, otherwise try to fix the issues in-place. Verbosity is controlled by args.verbose. + + @return: The number of failed checks. """ """ @@ -98,3 +100,5 @@ def run_pipeline_helper(): f"\n{yellow_color}Coverage: {coverage}% ({cnt_passed}/{cnt_implemented_checks} checks passed).{no_color}") sys.stdout.flush() + + return cnt_failed From 89ad299df745c9ed561e4dab76cf359d6354b98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 13:49:32 +0300 Subject: [PATCH 176/371] beman-tidy: expose as precommit hooks --- .pre-commit-config.yaml | 9 --------- .pre-commit-hooks.yaml | 6 ++++++ 2 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 .pre-commit-config.yaml create mode 100644 .pre-commit-hooks.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 41efdcfa..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -repos: - - repo: local - hooks: - - id: beman-tidy - name: Run beman-tidy on repo - entry: ./tools/beman-tidy/beman-tidy . - language: system - pass_filenames: false - always_run: true diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 00000000..17461153 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,6 @@ +- id: beman-tidy + name: Run beman-tidy on repo + entry: ./tools/beman-tidy/beman-tidy . + language: system + pass_filenames: false + always_run: true From 3c90ed138c85431a88d3e8381e4f48082729aacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 14:01:28 +0300 Subject: [PATCH 177/371] beman-tidy: lint --- tools/beman-tidy/beman-tidy | 5 ++++- tools/beman-tidy/lib/utils/git.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman-tidy index 3558b21c..5f622b76 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman-tidy @@ -7,6 +7,7 @@ import sys from lib.utils.git import get_repo_info, load_beman_standard_config from lib.pipeline import run_checks_pipeline + def parse_args(): """ Parse the CLI arguments. @@ -43,8 +44,10 @@ def main(): checks_to_run = [ check for check in beman_standard_check_config] if args.checks is None else args.checks - failed_checks = run_checks_pipeline(checks_to_run, args, beman_standard_check_config) + failed_checks = run_checks_pipeline( + checks_to_run, args, beman_standard_check_config) sys.exit(failed_checks) + if __name__ == "__main__": main() diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 21dbff88..08d4e170 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -57,12 +57,14 @@ def get_repo_info(path): f"An error occurred while getting repository information. Check {path}.") sys.exit(1) + def get_beman_standard_config_path(): """ Get the path to the Beman Standard YAML configuration file. """ return os.path.join(os.path.dirname(__file__), "..", "..", ".beman-standard.yml") + def load_beman_standard_config(path=get_beman_standard_config_path()): """ Load the Beman Standard YAML configuration file from the given path. From 4e5a17fcd39b49ad3565c93b87ad5c1a6e08d84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 14:01:50 +0300 Subject: [PATCH 178/371] beman-tidy: cleanup --- .pre-commit-hooks.yaml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .pre-commit-hooks.yaml diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml deleted file mode 100644 index 17461153..00000000 --- a/.pre-commit-hooks.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- id: beman-tidy - name: Run beman-tidy on repo - entry: ./tools/beman-tidy/beman-tidy . - language: system - pass_filenames: false - always_run: true From b4dcbf0f70cf991ff9293b431745eb722f0eea66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 15:07:45 +0300 Subject: [PATCH 179/371] beman-tidy: expose as precommit hooks --- .pre-commit-hooks.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .pre-commit-hooks.yaml diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 00000000..c30aa0dd --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,7 @@ +- id: beman-tidy + name: Run beman-tidy on repo + entry: ./tools/beman-tidy/beman-tidy + language: script + pass_filenames: false + always_run: true + args: [".", "--verbose"] From 6d6c2aa098238aa6a11644268bdee3c7944de38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 15:15:27 +0300 Subject: [PATCH 180/371] beman-tidy: rename precommit hook --- .pre-commit-hooks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index c30aa0dd..d327587c 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,5 +1,5 @@ - id: beman-tidy - name: Run beman-tidy on repo + name: "beman-tidy: bemanification your repo" entry: ./tools/beman-tidy/beman-tidy language: script pass_filenames: false From fb8618486b1957045724e5e37a91f609310caf51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 16:11:08 +0300 Subject: [PATCH 181/371] beman-tidy: rename CI job --- .github/workflows/beman-tidy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index f5eec8dc..651b6d59 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -name: Run Beman Tidy Tests +name: beman-tidy tests on: workflow_dispatch: From 1dcbac26d862c088caf5a4c851bcb26f7d41a16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 16:16:57 +0300 Subject: [PATCH 182/371] beman-tidy: remove impl for README.LIBRARY_STATUS --- .../lib/checks/beman_standard/readme.py | 25 -------------- tools/beman-tidy/lib/pipeline.py | 2 +- .../data/invalid/invalid-status-line-v1.md | 14 -------- .../data/invalid/invalid-status-line-v2.md | 15 -------- .../data/invalid/invalid-status-line-v3.md | 18 ---------- .../beman_standard/readme/test_readme.py | 34 +------------------ 6 files changed, 2 insertions(+), 106 deletions(-) delete mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md delete mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md delete mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index 84deacb5..f3db18a3 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -72,28 +72,3 @@ def fix(self): # TODO 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) - - def check(self): - """ - self.config["values"] contains a fixed set of Beman library statuses. - """ - statuses = self.config["values"] - assert len(statuses) == len(self.beman_library_maturity_model) - - # Check if at least one of the required status values is present. - status_count = len( - [status for status in statuses if self.has_content(status)]) - if status_count != 1: - self.log( - f"The file '{self.path}' does not contain exactly one of the required statuses from {statuses}") - return False - - return True - - def fix(self): - # TODO: Implement the fix. - pass diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 5dab18fa..7d99680b 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -13,7 +13,7 @@ # from .checks.beman_standard.file import # from .checks.beman_standard.general import # from .checks.beman_standard.license import -from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck +from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck # from .checks.beman_standard.release import # from .checks.beman_standard.toplevel import diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md deleted file mode 100644 index aa46bddb..00000000 --- a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md +++ /dev/null @@ -1,14 +0,0 @@ -## 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) - -**Purpose**: `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. - -This is NOT a valid README.md according to the Beman Standard: the library status is not properly formatted. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md deleted file mode 100644 index 6d3f668f..00000000 --- a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md +++ /dev/null @@ -1,15 +0,0 @@ -# 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) - -**Purpose**: `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) - -This is NOT a valid README.md according to the Beman Standard: the library status line has typos. - diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md deleted file mode 100644 index af1629a1..00000000 --- a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md +++ /dev/null @@ -1,18 +0,0 @@ -# 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) - -**Purpose**: `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), - -This is NOT a valid README.md according to the Beman Standard: the library status is duplicated. - diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py index 7e7f5d18..92e2b6f0 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -6,7 +6,7 @@ from tests.utils.file_testcase_runners import file_testcases_run_valid, file_testcases_run_invalid, file_testcases_run_fix_invalid # Actual tested checks. -from lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck +from lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck def test__README_TITLE__valid(repo_info, beman_standard_check_config): @@ -83,35 +83,3 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): """Test that the fix method corrects an invalid README.md badges""" pass - - -def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config, valid_readme_path): - """Test that a valid README.md library status passes the check""" - valid_readme_paths = [ - Path("tests/beman_standard/readme/data/valid/README-v1.md"), - Path("tests/beman_standard/readme/data/valid/README-v2.md"), - Path("tests/beman_standard/readme/data/valid/README-v3.md"), - Path("tests/beman_standard/readme/data/valid/README-v4.md"), - ] - - file_testcases_run_valid(valid_readme_paths, ReadmeLibraryStatusCheck, - 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""" - invalid_readme_paths = [ - Path("tests/beman_standard/readme/data/invalid/invalid.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md"), - ] - - file_testcases_run_invalid(invalid_readme_paths, ReadmeLibraryStatusCheck, - repo_info, beman_standard_check_config) - - -@pytest.mark.skip(reason="NOT implemented") -def test__README_LIBRARY_STATUS__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): - """Test that the fix method corrects an invalid README.md library status""" - pass From 5592d11eb3e8121261d72d1f0fe75901929bce3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 16:43:02 +0300 Subject: [PATCH 183/371] beman-tidy: add more TODOs --- .../lib/checks/beman_standard/cmake.py | 30 +++++++++++++++++++ .../lib/checks/beman_standard/cpp.py | 7 +++++ .../lib/checks/beman_standard/directory.py | 15 ++++++++++ .../lib/checks/beman_standard/file.py | 12 ++++++++ .../lib/checks/beman_standard/license.py | 16 ++++++++++ .../lib/checks/beman_standard/readme.py | 5 ++++ .../lib/checks/beman_standard/release.py | 9 ++++++ .../lib/checks/beman_standard/toplevel.py | 12 ++++++-- 8 files changed, 103 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/lib/checks/beman_standard/cmake.py index 174e963c..78c416f9 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cmake.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cmake.py @@ -3,14 +3,44 @@ from ..base.file_base_check import FileBaseCheck +# [CMAKE.*] checks category. +# All checks in this file extend the CMakeBaseCheck class. +# +# Note: CMakeBaseCheck is not a registered check! + + +class CMakeBaseCheck(FileBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "CMakeLists.txt") + # TODO CMAKE.DEFAULT + + # TODO CMAKE.USE_FETCH_CONTENT + + # TODO CMAKE.PROJECT_NAME + + # TODO CMAKE.PASSIVE_PROJECTS + + # TODO CMAKE.LIBRARY_NAME + + # TODO CMAKE.LIBRARY_ALIAS + + # TODO CMAKE.TARGET_NAMES + + # TODO CMAKE.PASSIVE_TARGETS + + # TODO CMAKE.SKIP_TESTS + + # TODO CMAKE.SKIP_EXAMPLES + + # TODO CMAKE.AVOID_PASSTHROUGHS diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/lib/checks/beman_standard/cpp.py index 41b76848..956cc13d 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/cpp.py +++ b/tools/beman-tidy/lib/checks/beman_standard/cpp.py @@ -1,6 +1,13 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# [CPP.*] checks category. + + # TODO CPP.NAMESPACE + + # TODO CPP.NO_FLAG_FORKING + + # TODO CPP.EXTENSION_IDENTIFIERS diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/lib/checks/beman_standard/directory.py index fa8b3150..9822e46d 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/lib/checks/beman_standard/directory.py @@ -3,10 +3,25 @@ from ..base.directory_base_check import DirectoryBaseCheck +# [DIRECTORY.*] checks category. + + # TODO DIRECTORY.INTERFACE_HEADERS + + # TODO DIRECTORY.IMPLEMENTATION_HEADERS + + # TODO DIRECTORY.SOURCES + + # TODO DIRECTORY.TESTS + + # TODO DIRECTORY.EXAMPLES + + # TODO DIRECTORY.DOCS + + # TODO DIRECTORY.PAPERS diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/lib/checks/beman_standard/file.py index 2f461ae9..f97ee87d 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/file.py +++ b/tools/beman-tidy/lib/checks/beman_standard/file.py @@ -3,7 +3,19 @@ from ..base.file_base_check import FileBaseCheck +# [FILE.*] checks category. +# All checks in this file extend the FileBaseCheck class. +# +# Note: FileBaseCheck is not a registered check! + + # TODO FILE.NAMES + + # TODO FILE.TEST_NAMES + + # TODO FILE.LICENSE_ID + + # TODO FILE.COPYRIGHT diff --git a/tools/beman-tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/lib/checks/beman_standard/license.py index 46b26ea2..51e96a77 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/lib/checks/beman_standard/license.py @@ -1,6 +1,22 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from ..base.file_base_check import FileBaseCheck + +# [LICENSE.*] checks category. +# All checks in this file extend the LicenseBaseCheck class. +# +# Note: LicenseBaseCheck is not a registered check! + + +class LicenseBaseCheck(FileBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "LICENSE") + # TODO LICENSE.APPROVED + + # TODO LICENSE.APACHE_LLVM + + # TODO LICENSE.CRITERIA diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/lib/checks/beman_standard/readme.py index f3db18a3..33ec4d19 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/lib/checks/beman_standard/readme.py @@ -6,6 +6,11 @@ from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check +# [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): diff --git a/tools/beman-tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/lib/checks/beman_standard/release.py index e2e13e48..d2f3150a 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/lib/checks/beman_standard/release.py @@ -3,6 +3,15 @@ from ..base.file_base_check import FileBaseCheck +# [RELEASE.*] checks category. +# Note: Data is stored online - e.g. https://github.com/bemanproject/exemplar/releases +# TBD - Do we want to implement these checks? + + # TODO RELEASE.GITHUB + + # TODO RELEASE.NOTES + + # TODO RELEASE.GODBOLT_TRUNK_VERSION diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index 289e6175..f3cd6127 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -3,6 +3,12 @@ from ..base.file_base_check import FileBaseCheck -# TODO TOPLEVEL.CMAKE -# TODO TOPLEVEL.LICENSE -# TODO TOPLEVEL.README +# [TOPLEVEL.*] checks category. + +# TODO TOPLEVEL.CMAKE - use CMakeBaseCheck + + +# TODO TOPLEVEL.LICENSE - use FileBaseCheck + + +# TODO TOPLEVEL.README - use ReadmeBaseCheck From d35f6de1cc182f18fc5555419c44e385ff9c7e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 18:52:54 +0300 Subject: [PATCH 184/371] beman-tidy: tweaks in docs --- tools/beman-tidy/lib/checks/base/base_check.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/lib/checks/base/base_check.py index 6bc5c50b..493da42b 100644 --- a/tools/beman-tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/lib/checks/base/base_check.py @@ -58,6 +58,8 @@ def pre_check(self): """ Pre-checks if this rule is properly initialized. Usually, this is internal use only. + + Note: This method is internally called by the framework. """ if self.name is None: self.log("The name is not set.") @@ -79,6 +81,8 @@ 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. """ pass @@ -88,6 +92,9 @@ 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 + is too difficult to implement or does not make sense. """ pass From 1f4fda2481185f0ab17f0b3db65439a64410158a Mon Sep 17 00:00:00 2001 From: rishyak Date: Mon, 9 Jun 2025 16:56:14 -0400 Subject: [PATCH 185/371] beman-tidy: support for pyproject.toml and uv - We no longer need Makefiles - No need for requirements.txt files, better lockfiles instead Signed-off-by: rishyak --- .github/workflows/beman-tidy.yml | 25 +- tools/beman-tidy/.python-version | 1 + tools/beman-tidy/Makefile | 34 --- tools/beman-tidy/README.md | 57 ++-- .../beman-tidy/{beman-tidy => beman_tidy.py} | 33 ++- tools/beman-tidy/pylock.toml | 172 +++++++++++++ tools/beman-tidy/pyproject.toml | 27 ++ tools/beman-tidy/requirements-dev.txt | 1 - tools/beman-tidy/requirements.txt | 4 - tools/beman-tidy/uv.lock | 243 ++++++++++++++++++ 10 files changed, 509 insertions(+), 88 deletions(-) create mode 100644 tools/beman-tidy/.python-version delete mode 100755 tools/beman-tidy/Makefile rename tools/beman-tidy/{beman-tidy => beman_tidy.py} (61%) create mode 100644 tools/beman-tidy/pylock.toml create mode 100644 tools/beman-tidy/pyproject.toml delete mode 100644 tools/beman-tidy/requirements-dev.txt delete mode 100644 tools/beman-tidy/requirements.txt create mode 100644 tools/beman-tidy/uv.lock diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index 651b6d59..74582627 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -3,29 +3,32 @@ name: beman-tidy tests on: - workflow_dispatch: + push: pull_request: + workflow_dispatch: jobs: tests: runs-on: ubuntu-latest + defaults: + run: + working-directory: tools/beman-tidy steps: - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies (production) - run: | - make -C tools/beman-tidy install + - name: Install uv + uses: astral-sh/setup-uv@v5 - - name: Install dependencies (development) + - name: Sync environment run: | - make -C tools/beman-tidy install-dev + uv sync - - name: Run linter - run: | - echo "Running linter..." - make -C tools/beman-tidy self-lint + # - name: Run linter + # run: | + # echo "Running linter" + # uv run ruff check --diff - name: Run tests run: | - make -C tools/beman-tidy test + uv run pytest tests/ -v diff --git a/tools/beman-tidy/.python-version b/tools/beman-tidy/.python-version new file mode 100644 index 00000000..24ee5b1b --- /dev/null +++ b/tools/beman-tidy/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/tools/beman-tidy/Makefile b/tools/beman-tidy/Makefile deleted file mode 100755 index 9b06e6a7..00000000 --- a/tools/beman-tidy/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# Default target: install and run tests. -all: install test - -# Install tool: -install: - @echo "Installing production dependencies..." - pip3 install -r requirements.txt &> /dev/null - -# Install development dependencies: -install-dev: - @echo "Installing development dependencies..." - pip3 install -r requirements-dev.txt &> /dev/null - brew install autopep8 &> /dev/null - apt-get install autopep8 -y &> /dev/null - pip3 install autopep8 - -# Run tests: -test: - @echo "Running tests..." - python3 -m pytest tests/ -v - -# Run linter: -self-lint: - @echo "Running linter..." - @pwd - find . -name "*.py" -or -name "beman-tidy" | xargs autopep8 --exit-code --diff - -# Run lint-fix: -self-lint-fix: - @echo "Running linter-fix..." - @pwd - find . -name "*.py" -or -name "beman-tidy" | xargs autopep8 --in-place diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 2dc4e796..fa648855 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -22,23 +22,24 @@ $ pip3 install -r requirements.txt ## Usage * Display help: -```shell -$ ./beman-tidy --help -usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path - -positional arguments: - repo_path path to the repository to check - -optional arguments: - -h, --help show this help message and exit - --fix-inplace, --no-fix-inplace - Try to automatically fix found issues (default: False) - --verbose, --no-verbose - print verbose output for each check (default: False) - --checks CHECKS array of checks to run -``` -* Run beman-tidy on the exemplar repository (default: dry-run mode) + ```console + $ uv run beman-tidy --help + usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path + + positional arguments: + repo_path path to the repository to check + + optional arguments: + -h, --help show this help message and exit + --fix-inplace, --no-fix-inplace + Try to automatically fix found issues (default: False) + --verbose, --no-verbose + print verbose output for each check (default: False) + --checks CHECKS array of checks to run + ``` + +* Run beman-tidy on the exemplar repository **(default: dry-run mode)** ```shell $ ./beman-tidy ../../../exemplar @@ -51,20 +52,20 @@ Coverage: 66.67% (2/3 checks passed). $ ./beman-tidy /path/to/exemplar --verbose beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... -[WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. - check [RECOMMENDATION][README.TITLE] ... FAILED + Running check [RECOMMENDATION][README.TITLE] ... + [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. + check [RECOMMENDATION][README.TITLE] ... FAILED -Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED + Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED -beman-tidy pipeline finished. + beman-tidy pipeline finished. -Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). + Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). Coverage: 66.67% (2/3 checks passed). @@ -91,9 +92,9 @@ Coverage: 100.0% (3/3 checks passed). * Run beman-tidy on the exemplar repository (fix issues in-place): -```shell -$ ./beman-tidy ../exemplar --fix-inplace --verbose -``` + ```console + $ uv run beman-tidy path/to/exemplar --fix-inplace --verbose + ``` ## beman-tidy Development diff --git a/tools/beman-tidy/beman-tidy b/tools/beman-tidy/beman_tidy.py similarity index 61% rename from tools/beman-tidy/beman-tidy rename to tools/beman-tidy/beman_tidy.py index 5f622b76..862c0602 100755 --- a/tools/beman-tidy/beman-tidy +++ b/tools/beman-tidy/beman_tidy.py @@ -14,14 +14,24 @@ def parse_args(): """ parser = argparse.ArgumentParser() - parser.add_argument("repo_path", help="path to the repository to check", - type=str) - parser.add_argument("--fix-inplace", help="Try to automatically fix found issues", - action=argparse.BooleanOptionalAction, type=bool, default=False) - parser.add_argument("--verbose", help="print verbose output for each check", - action=argparse.BooleanOptionalAction, type=bool, default=False) - parser.add_argument("--checks", help="array of checks to run", - type=str, default=None) + parser.add_argument("repo_path", help="path to the repository to check", type=str) + parser.add_argument( + "--fix-inplace", + help="Try to automatically fix found issues", + action=argparse.BooleanOptionalAction, + type=bool, + default=False, + ) + parser.add_argument( + "--verbose", + help="print verbose output for each check", + action=argparse.BooleanOptionalAction, + type=bool, + default=False, + ) + parser.add_argument( + "--checks", help="array of checks to run", type=str, default=None + ) args = parser.parse_args() args.repo_info = get_repo_info(args.repo_path) @@ -41,8 +51,11 @@ def main(): print("Failed to download the beman standard. STOP.") return - checks_to_run = [ - check for check in beman_standard_check_config] if args.checks is None else args.checks + checks_to_run = ( + [check for check in beman_standard_check_config] + if args.checks is None + else args.checks + ) failed_checks = run_checks_pipeline( checks_to_run, args, beman_standard_check_config) diff --git a/tools/beman-tidy/pylock.toml b/tools/beman-tidy/pylock.toml new file mode 100644 index 00000000..62d517fe --- /dev/null +++ b/tools/beman-tidy/pylock.toml @@ -0,0 +1,172 @@ +# This file was autogenerated by uv via the following command: +# uv export -o pylock.toml +lock-version = "1.0" +created-by = "uv" +requires-python = ">=3.13" + +[[packages]] +name = "beman-tidy" +directory = { path = ".", editable = true } + +[[packages]] +name = "certifi" +version = "2025.4.26" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", upload-time = 2025-04-26T02:12:29Z, size = 160705, hashes = { sha256 = "0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", upload-time = 2025-04-26T02:12:27Z, size = 159618, hashes = { sha256 = "30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3" } }] + +[[packages]] +name = "charset-normalizer" +version = "3.4.2" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", upload-time = 2025-05-02T08:34:42Z, size = 126367, hashes = { sha256 = "5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63" } } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", upload-time = 2025-05-02T08:32:56Z, size = 199622, hashes = { sha256 = "926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0" } }, + { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-05-02T08:32:58Z, size = 143435, hashes = { sha256 = "eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf" } }, + { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-05-02T08:33:00Z, size = 153653, hashes = { sha256 = "3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e" } }, + { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-05-02T08:33:02Z, size = 146231, hashes = { sha256 = "98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1" } }, + { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-05-02T08:33:04Z, size = 148243, hashes = { sha256 = "6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c" } }, + { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", upload-time = 2025-05-02T08:33:06Z, size = 150442, hashes = { sha256 = "e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691" } }, + { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", upload-time = 2025-05-02T08:33:08Z, size = 145147, hashes = { sha256 = "1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0" } }, + { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", upload-time = 2025-05-02T08:33:09Z, size = 153057, hashes = { sha256 = "ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b" } }, + { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", upload-time = 2025-05-02T08:33:11Z, size = 156454, hashes = { sha256 = "32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff" } }, + { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", upload-time = 2025-05-02T08:33:13Z, size = 154174, hashes = { sha256 = "289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b" } }, + { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", upload-time = 2025-05-02T08:33:15Z, size = 149166, hashes = { sha256 = "4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148" } }, + { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", upload-time = 2025-05-02T08:33:17Z, size = 98064, hashes = { sha256 = "aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7" } }, + { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", upload-time = 2025-05-02T08:33:18Z, size = 105641, hashes = { sha256 = "aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980" } }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", upload-time = 2025-05-02T08:34:40Z, size = 52626, hashes = { sha256 = "7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0" } }, +] + +[[packages]] +name = "colorama" +version = "0.4.6" +marker = "sys_platform == 'win32'" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", upload-time = 2022-10-25T02:36:22Z, size = 27697, hashes = { sha256 = "08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", upload-time = 2022-10-25T02:36:20Z, size = 25335, hashes = { sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" } }] + +[[packages]] +name = "gitdb" +version = "4.0.12" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", upload-time = 2025-01-02T07:20:46Z, size = 394684, hashes = { sha256 = "5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", upload-time = 2025-01-02T07:20:43Z, size = 62794, hashes = { sha256 = "67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf" } }] + +[[packages]] +name = "gitpython" +version = "3.1.44" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", upload-time = 2025-01-02T07:32:43Z, size = 214196, hashes = { sha256 = "c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269" } } +wheels = [{ name = "gitpython-3.1.44-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", upload-time = 2025-01-02T07:32:40Z, size = 207599, hashes = { sha256 = "9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110" } }] + +[[packages]] +name = "idna" +version = "3.10" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", upload-time = 2024-09-15T18:07:39Z, size = 190490, hashes = { sha256 = "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", upload-time = 2024-09-15T18:07:37Z, size = 70442, hashes = { sha256 = "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" } }] + +[[packages]] +name = "iniconfig" +version = "2.1.0" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", upload-time = 2025-03-19T20:09:59Z, size = 4793, hashes = { sha256 = "3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", upload-time = 2025-03-19T20:10:01Z, size = 6050, hashes = { sha256 = "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" } }] + +[[packages]] +name = "markdown" +version = "3.4.4" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/87/2a/62841f4fb1fef5fa015ded48d02401cd95643ca03b6760b29437b62a04a4/Markdown-3.4.4.tar.gz", upload-time = 2023-07-25T15:13:45Z, size = 324459, hashes = { sha256 = "225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6" } } +wheels = [{ name = "markdown-3.4.4-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/1a/b5/228c1cdcfe138f1a8e01ab1b54284c8b83735476cb22b6ba251656ed13ad/Markdown-3.4.4-py3-none-any.whl", upload-time = 2023-07-25T15:13:43Z, size = 94174, hashes = { sha256 = "a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941" } }] + +[[packages]] +name = "packaging" +version = "25.0" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", upload-time = 2025-04-19T11:48:59Z, size = 165727, hashes = { sha256 = "d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", upload-time = 2025-04-19T11:48:57Z, size = 66469, hashes = { sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" } }] + +[[packages]] +name = "pluggy" +version = "1.6.0" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", upload-time = 2025-05-15T12:30:07Z, size = 69412, hashes = { sha256 = "7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", upload-time = 2025-05-15T12:30:06Z, size = 20538, hashes = { sha256 = "e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" } }] + +[[packages]] +name = "pygments" +version = "2.19.1" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", upload-time = 2025-01-06T17:26:30Z, size = 4968581, hashes = { sha256 = "61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", upload-time = 2025-01-06T17:26:25Z, size = 1225293, hashes = { sha256 = "9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" } }] + +[[packages]] +name = "pytest" +version = "8.4.0" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/fb/aa/405082ce2749be5398045152251ac69c0f3578c7077efc53431303af97ce/pytest-8.4.0.tar.gz", upload-time = 2025-06-02T17:36:30Z, size = 1515232, hashes = { sha256 = "14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl", upload-time = 2025-06-02T17:36:27Z, size = 363797, hashes = { sha256 = "f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e" } }] + +[[packages]] +name = "pyyaml" +version = "6.0.2" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", upload-time = 2024-08-06T20:33:50Z, size = 130631, hashes = { sha256 = "d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e" } } +wheels = [ + { name = "pyyaml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", upload-time = 2024-08-06T20:32:43Z, size = 181309, hashes = { sha256 = "efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba" } }, + { name = "pyyaml-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", upload-time = 2024-08-06T20:32:44Z, size = 171679, hashes = { sha256 = "50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1" } }, + { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2024-08-06T20:32:46Z, size = 733428, hashes = { sha256 = "0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133" } }, + { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2024-08-06T20:32:51Z, size = 763361, hashes = { sha256 = "17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484" } }, + { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-08-06T20:32:53Z, size = 759523, hashes = { sha256 = "70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5" } }, + { name = "pyyaml-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", upload-time = 2024-08-06T20:32:54Z, size = 726660, hashes = { sha256 = "41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc" } }, + { name = "pyyaml-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", upload-time = 2024-08-06T20:32:56Z, size = 751597, hashes = { sha256 = "68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652" } }, + { name = "pyyaml-6.0.2-cp313-cp313-win32.whl", url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", upload-time = 2024-08-06T20:33:03Z, size = 140527, hashes = { sha256 = "bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183" } }, + { name = "pyyaml-6.0.2-cp313-cp313-win_amd64.whl", url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", upload-time = 2024-08-06T20:33:04Z, size = 156446, hashes = { sha256 = "8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563" } }, +] + +[[packages]] +name = "requests" +version = "2.32.3" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", upload-time = 2024-05-29T15:37:49Z, size = 131218, hashes = { sha256 = "55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", upload-time = 2024-05-29T15:37:47Z, size = 64928, hashes = { sha256 = "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" } }] + +[[packages]] +name = "ruff" +version = "0.11.13" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", upload-time = 2025-06-05T21:00:15Z, size = 4282054, hashes = { sha256 = "26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514" } } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", upload-time = 2025-06-05T20:59:32Z, size = 10292516, hashes = { sha256 = "4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46" } }, + { url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", upload-time = 2025-06-05T20:59:37Z, size = 11106083, hashes = { sha256 = "aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48" } }, + { url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", upload-time = 2025-06-05T20:59:39Z, size = 10436024, hashes = { sha256 = "53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b" } }, + { url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-06-05T20:59:42Z, size = 10646324, hashes = { sha256 = "ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a" } }, + { url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", upload-time = 2025-06-05T20:59:44Z, size = 10174416, hashes = { sha256 = "6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc" } }, + { url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", upload-time = 2025-06-05T20:59:46Z, size = 11724197, hashes = { sha256 = "1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629" } }, + { url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", upload-time = 2025-06-05T20:59:49Z, size = 12511615, hashes = { sha256 = "d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933" } }, + { url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-06-05T20:59:51Z, size = 12117080, hashes = { sha256 = "55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165" } }, + { url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-06-05T20:59:54Z, size = 11326315, hashes = { sha256 = "633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71" } }, + { url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-06-05T20:59:56Z, size = 11555640, hashes = { sha256 = "4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9" } }, + { url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", upload-time = 2025-06-05T20:59:59Z, size = 10507364, hashes = { sha256 = "4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc" } }, + { url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", upload-time = 2025-06-05T21:00:01Z, size = 10141462, hashes = { sha256 = "d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7" } }, + { url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", upload-time = 2025-06-05T21:00:04Z, size = 11121028, hashes = { sha256 = "26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432" } }, + { url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", upload-time = 2025-06-05T21:00:06Z, size = 11602992, hashes = { sha256 = "51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492" } }, + { url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", upload-time = 2025-06-05T21:00:08Z, size = 10474944, hashes = { sha256 = "96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250" } }, + { url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", upload-time = 2025-06-05T21:00:11Z, size = 11548669, hashes = { sha256 = "29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3" } }, + { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", upload-time = 2025-06-05T21:00:13Z, size = 10683928, hashes = { sha256 = "b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b" } }, +] + +[[packages]] +name = "smmap" +version = "5.0.2" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", upload-time = 2025-01-02T07:14:40Z, size = 22329, hashes = { sha256 = "26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", upload-time = 2025-01-02T07:14:38Z, size = 24303, hashes = { sha256 = "b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e" } }] + +[[packages]] +name = "urllib3" +version = "2.4.0" +index = "https://pypi.org/simple" +sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", upload-time = 2025-04-10T15:23:39Z, size = 390672, hashes = { sha256 = "414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", upload-time = 2025-04-10T15:23:37Z, size = 128680, hashes = { sha256 = "4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813" } }] diff --git a/tools/beman-tidy/pyproject.toml b/tools/beman-tidy/pyproject.toml new file mode 100644 index 00000000..b2a78059 --- /dev/null +++ b/tools/beman-tidy/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "beman-tidy" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +authors = [{ name = "Darius Neațu", email = "neatudarius@gmail.com" }] +maintainers = [{ name = "Rishyak", email = "hello@rishyak.com" }] +dependencies = [ + "gitpython==3.1.44", + "markdown==3.4.4", + "pyyaml==6.0.2", + "requests==2.32.3", +] + +[build-system] +requires = ["flit_core >=3.2,<4"] +build-backend = "flit_core.buildapi" + +[dependency-groups] +dev = ["pytest>=8.4.0", "ruff>=0.11.13"] + +[project.scripts] +beman-tidy = "beman_tidy:main" + +[tool.pytest.ini_options] +addopts = "-v" diff --git a/tools/beman-tidy/requirements-dev.txt b/tools/beman-tidy/requirements-dev.txt deleted file mode 100644 index 69d461f3..00000000 --- a/tools/beman-tidy/requirements-dev.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.4.0 diff --git a/tools/beman-tidy/requirements.txt b/tools/beman-tidy/requirements.txt deleted file mode 100644 index 65b6c5cd..00000000 --- a/tools/beman-tidy/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -GitPython==3.1.44 -Markdown==3.4.4 -Requests==2.32.3 -pyyaml==6.0.2 diff --git a/tools/beman-tidy/uv.lock b/tools/beman-tidy/uv.lock new file mode 100644 index 00000000..0662e748 --- /dev/null +++ b/tools/beman-tidy/uv.lock @@ -0,0 +1,243 @@ +version = 1 +revision = 2 +requires-python = ">=3.13" + +[[package]] +name = "beman-tidy" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "gitpython" }, + { name = "markdown" }, + { name = "pyyaml" }, + { name = "requests" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "gitpython", specifier = "==3.1.44" }, + { name = "markdown", specifier = "==3.4.4" }, + { name = "pyyaml", specifier = "==6.0.2" }, + { name = "requests", specifier = "==2.32.3" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.4.0" }, + { name = "ruff", specifier = ">=0.11.13" }, +] + +[[package]] +name = "certifi" +version = "2025.4.26" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, + { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, + { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, + { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, + { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, + { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, + { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, + { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, +] + +[[package]] +name = "gitpython" +version = "3.1.44" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196, upload-time = "2025-01-02T07:32:43.59Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599, upload-time = "2025-01-02T07:32:40.731Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "markdown" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/2a/62841f4fb1fef5fa015ded48d02401cd95643ca03b6760b29437b62a04a4/Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6", size = 324459, upload-time = "2023-07-25T15:13:45.311Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/b5/228c1cdcfe138f1a8e01ab1b54284c8b83735476cb22b6ba251656ed13ad/Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941", size = 94174, upload-time = "2023-07-25T15:13:43.124Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/aa/405082ce2749be5398045152251ac69c0f3578c7077efc53431303af97ce/pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6", size = 1515232, upload-time = "2025-06-02T17:36:30.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e", size = 363797, upload-time = "2025-06-02T17:36:27.859Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, +] + +[[package]] +name = "ruff" +version = "0.11.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514", size = 4282054, upload-time = "2025-06-05T21:00:15.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46", size = 10292516, upload-time = "2025-06-05T20:59:32.944Z" }, + { url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48", size = 11106083, upload-time = "2025-06-05T20:59:37.03Z" }, + { url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b", size = 10436024, upload-time = "2025-06-05T20:59:39.741Z" }, + { url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a", size = 10646324, upload-time = "2025-06-05T20:59:42.185Z" }, + { url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc", size = 10174416, upload-time = "2025-06-05T20:59:44.319Z" }, + { url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629", size = 11724197, upload-time = "2025-06-05T20:59:46.935Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933", size = 12511615, upload-time = "2025-06-05T20:59:49.534Z" }, + { url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165", size = 12117080, upload-time = "2025-06-05T20:59:51.654Z" }, + { url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71", size = 11326315, upload-time = "2025-06-05T20:59:54.469Z" }, + { url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9", size = 11555640, upload-time = "2025-06-05T20:59:56.986Z" }, + { url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc", size = 10507364, upload-time = "2025-06-05T20:59:59.154Z" }, + { url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7", size = 10141462, upload-time = "2025-06-05T21:00:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432", size = 11121028, upload-time = "2025-06-05T21:00:04.06Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492", size = 11602992, upload-time = "2025-06-05T21:00:06.249Z" }, + { url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250", size = 10474944, upload-time = "2025-06-05T21:00:08.459Z" }, + { url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3", size = 11548669, upload-time = "2025-06-05T21:00:11.147Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" }, +] + +[[package]] +name = "smmap" +version = "5.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, +] + +[[package]] +name = "urllib3" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, +] From 889aa13037fb5934cfa8ce3ac16df30d33db77d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 13:43:13 +0300 Subject: [PATCH 186/371] beman-tidy: ruff linter tweaks (#1) --- .github/workflows/beman-tidy.yml | 8 ++++---- tools/beman-tidy/lib/checks/base/directory_base_check.py | 2 +- tools/beman-tidy/lib/checks/base/file_base_check.py | 6 +++--- tools/beman-tidy/lib/checks/beman_standard/directory.py | 2 -- tools/beman-tidy/lib/checks/beman_standard/file.py | 2 -- tools/beman-tidy/lib/checks/beman_standard/release.py | 2 -- tools/beman-tidy/lib/checks/beman_standard/toplevel.py | 2 -- tools/beman-tidy/lib/pipeline.py | 4 ++-- tools/beman-tidy/lib/utils/git.py | 2 +- tools/beman-tidy/tests/beman_standard/readme/conftest.py | 3 +-- 10 files changed, 12 insertions(+), 21 deletions(-) diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index 74582627..4fc73693 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -24,10 +24,10 @@ jobs: run: | uv sync - # - name: Run linter - # run: | - # echo "Running linter" - # uv run ruff check --diff + - name: Run linter + run: | + echo "Running linter" + uv run ruff check --diff - name: Run tests run: | diff --git a/tools/beman-tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/lib/checks/base/directory_base_check.py index 3b16f443..37f1023f 100644 --- a/tools/beman-tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/lib/checks/base/directory_base_check.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from abc import ABC, abstractmethod +from abc import abstractmethod import os from .base_check import BaseCheck diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/lib/checks/base/file_base_check.py index 879b68f0..07e9b83d 100644 --- a/tools/beman-tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/lib/checks/base/file_base_check.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from abc import ABC, abstractmethod +from abc import abstractmethod import os import re @@ -62,7 +62,7 @@ def read(self): try: with open(self.path, 'r') as file: return file.read() - except Exception as e: + except Exception: return "" def read_lines(self): @@ -72,7 +72,7 @@ def read_lines(self): try: with open(self.path, 'r') as file: return file.readlines() - except Exception as e: + except Exception: return [] def read_lines_strip(self): diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/lib/checks/beman_standard/directory.py index 9822e46d..f7d0d474 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/lib/checks/beman_standard/directory.py @@ -1,8 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.directory_base_check import DirectoryBaseCheck - # [DIRECTORY.*] checks category. diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/lib/checks/beman_standard/file.py index f97ee87d..183e8977 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/file.py +++ b/tools/beman-tidy/lib/checks/beman_standard/file.py @@ -1,8 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.file_base_check import FileBaseCheck - # [FILE.*] checks category. # All checks in this file extend the FileBaseCheck class. # diff --git a/tools/beman-tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/lib/checks/beman_standard/release.py index d2f3150a..bc4403b5 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/lib/checks/beman_standard/release.py @@ -1,8 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.file_base_check import FileBaseCheck - # [RELEASE.*] checks category. # Note: Data is stored online - e.g. https://github.com/bemanproject/exemplar/releases # TBD - Do we want to implement these checks? diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py index f3cd6127..63f15ce4 100644 --- a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/lib/checks/beman_standard/toplevel.py @@ -1,8 +1,6 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.file_base_check import FileBaseCheck - # [TOPLEVEL.*] checks category. # TODO TOPLEVEL.CMAKE - use CMakeBaseCheck diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 7d99680b..150bd7ad 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -13,7 +13,7 @@ # from .checks.beman_standard.file import # from .checks.beman_standard.general import # from .checks.beman_standard.license import -from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck +from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck # noqa: F401 # from .checks.beman_standard.release import # from .checks.beman_standard.toplevel import @@ -77,7 +77,7 @@ def run_pipeline_helper(): cnt_failed = 0 cnt_skipped = cnt_all_beman_standard_checks - cnt_implemented_checks for check_name in checks_to_run: - if not check_name in implemented_checks: + if check_name not in implemented_checks: continue if run_check(implemented_checks[check_name]): diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/lib/utils/git.py index 08d4e170..18b40434 100644 --- a/tools/beman-tidy/lib/utils/git.py +++ b/tools/beman-tidy/lib/utils/git.py @@ -52,7 +52,7 @@ def get_repo_info(path): except InvalidGitRepositoryError: print(f"The path '{path}' is not inside a valid Git repository.") sys.exit(1) - except Exception as e: + except Exception: print( f"An error occurred while getting repository information. Check {path}.") sys.exit(1) diff --git a/tools/beman-tidy/tests/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/beman_standard/readme/conftest.py index 28be98cc..55e9d206 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/beman_standard/readme/conftest.py @@ -1,11 +1,10 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -import os import pytest from pathlib import Path -from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config +from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 @pytest.fixture From 006c3183895ac10cd66eed7cba3f58085fed09a8 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 00:39:24 -0400 Subject: [PATCH 187/371] docs(beman-tidy): uv-ify docs Signed-off-by: rishyak --- tools/beman-tidy/README.md | 78 ++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index fa648855..0a756ace 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -13,11 +13,14 @@ Note: `2025-06-07`: In order to make the best and quickly use of the tool in the ## Installation -```shell -$ make install -# or -$ pip3 install -r requirements.txt -``` +- The current recommended workflow relies on [Astral's uv](https://docs.astral.sh/uv/) +- However, we provide a [PEP 751](https://peps.python.org/pep-0751/) `pylock.toml`, so don't feel forced to use uv +- You can use beman-tidy as a pre-commit hook or install it on your system using `pipx` + + ```console + $ uv build + $ pipx install path/to/wheel + ``` ## Usage @@ -41,54 +44,57 @@ $ pip3 install -r requirements.txt * Run beman-tidy on the exemplar repository **(default: dry-run mode)** -```shell -$ ./beman-tidy ../../../exemplar -# non-verbose mode -Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). + ```shell + $ uv run beman-tidy path/to/exemplar + # non-verbose mode + Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). -Coverage: 66.67% (2/3 checks passed). + Coverage: 66.67% (2/3 checks passed). -# verbose mode - no errors -$ ./beman-tidy /path/to/exemplar --verbose -beman-tidy pipeline started ... + # verbose mode - no errors + $ ./beman-tidy /path/to/exemplar --verbose + beman-tidy pipeline started ... - Running check [RECOMMENDATION][README.TITLE] ... - [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. - check [RECOMMENDATION][README.TITLE] ... FAILED + Running check [RECOMMENDATION][README.TITLE] ... + [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. + check [RECOMMENDATION][README.TITLE] ... FAILED - Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED + Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED - Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED - beman-tidy pipeline finished. + beman-tidy pipeline finished. - Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). + Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). -Coverage: 66.67% (2/3 checks passed). + Coverage: 66.67% (2/3 checks passed). + ``` + +- Run beman-tidy in verbose mode -# verbose mode - with errors -$ ./beman-tidy /path/to/exemplar --verbose -beman-tidy pipeline started ... + ```console + $ ./beman-tidy /path/to/exemplar --verbose + beman-tidy pipeline started ... -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED + Running check [RECOMMENDATION][README.TITLE] ... + check [RECOMMENDATION][README.TITLE] ... PASSED -Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED + Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED -beman-tidy pipeline finished. + beman-tidy pipeline finished. -Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). + Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). -Coverage: 100.0% (3/3 checks passed). -``` + Coverage: 100.0% (3/3 checks passed). + ``` * Run beman-tidy on the exemplar repository (fix issues in-place): From 85c46d2722aebb7f3512d768a4bf4ed6ecc98ea2 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 00:53:23 -0400 Subject: [PATCH 188/371] fix: remove non-existent identifier Signed-off-by: rishyak --- tools/beman-tidy/lib/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/lib/pipeline.py index 150bd7ad..fc51c859 100644 --- a/tools/beman-tidy/lib/pipeline.py +++ b/tools/beman-tidy/lib/pipeline.py @@ -13,7 +13,7 @@ # from .checks.beman_standard.file import # from .checks.beman_standard.general import # from .checks.beman_standard.license import -from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck # noqa: F401 +from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck # noqa: F401 # from .checks.beman_standard.release import # from .checks.beman_standard.toplevel import From 0059f304cc6342e93fbeea3a042f32e5cfa9ece7 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 00:54:19 -0400 Subject: [PATCH 189/371] build: bump python Signed-off-by: rishyak --- tools/beman-tidy/.python-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/.python-version b/tools/beman-tidy/.python-version index 24ee5b1b..6324d401 100644 --- a/tools/beman-tidy/.python-version +++ b/tools/beman-tidy/.python-version @@ -1 +1 @@ -3.13 +3.14 From d04af1cb85291a3e92467289907cf23e8923309b Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 00:54:46 -0400 Subject: [PATCH 190/371] build(deps): sync lockfiles Signed-off-by: rishyak --- tools/beman-tidy/pylock.toml | 6 +++--- tools/beman-tidy/uv.lock | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/beman-tidy/pylock.toml b/tools/beman-tidy/pylock.toml index 62d517fe..53a6e4a1 100644 --- a/tools/beman-tidy/pylock.toml +++ b/tools/beman-tidy/pylock.toml @@ -10,10 +10,10 @@ directory = { path = ".", editable = true } [[packages]] name = "certifi" -version = "2025.4.26" +version = "2025.6.15" index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", upload-time = 2025-04-26T02:12:29Z, size = 160705, hashes = { sha256 = "0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", upload-time = 2025-04-26T02:12:27Z, size = 159618, hashes = { sha256 = "30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3" } }] +sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", upload-time = 2025-06-15T02:45:51Z, size = 158753, hashes = { sha256 = "d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", upload-time = 2025-06-15T02:45:49Z, size = 157650, hashes = { sha256 = "2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057" } }] [[packages]] name = "charset-normalizer" diff --git a/tools/beman-tidy/uv.lock b/tools/beman-tidy/uv.lock index 0662e748..a4ad32b9 100644 --- a/tools/beman-tidy/uv.lock +++ b/tools/beman-tidy/uv.lock @@ -35,11 +35,11 @@ dev = [ [[package]] name = "certifi" -version = "2025.4.26" +version = "2025.6.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, + { url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" }, ] [[package]] From fe6b4bf6667ac6a7f11a6aaea2e4ec9f485e345e Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 01:03:22 -0400 Subject: [PATCH 191/371] fix(beman-tidy): remove disallowed 'type' argument from BooleanOptionalAction - `type` param of `argparse.BooleanOptionalAction` are deprecated and will be removed in Python 3.14 - https://docs.python.org/3.14/deprecations/pending-removal-in-3.14.html Signed-off-by: rishyak --- tools/beman-tidy/beman_tidy.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy.py b/tools/beman-tidy/beman_tidy.py index 862c0602..dd9819e7 100755 --- a/tools/beman-tidy/beman_tidy.py +++ b/tools/beman-tidy/beman_tidy.py @@ -19,14 +19,12 @@ def parse_args(): "--fix-inplace", help="Try to automatically fix found issues", action=argparse.BooleanOptionalAction, - type=bool, default=False, ) parser.add_argument( "--verbose", help="print verbose output for each check", action=argparse.BooleanOptionalAction, - type=bool, default=False, ) parser.add_argument( From 1f569cbbc2b400fcaa4accaae45bb2e99441e9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 17 Jun 2025 14:50:29 +0300 Subject: [PATCH 192/371] [beman-tidy] beman-tidy: improve docs and examples (#2) --- .gitignore | 3 + tools/beman-tidy/README.md | 129 +++++++++++------- tools/beman-tidy/docs/dev-guide.md | 35 ++--- tools/beman-tidy/pyproject.toml | 2 +- .../tests/beman_standard/readme/conftest.py | 4 +- 5 files changed, 98 insertions(+), 75 deletions(-) diff --git a/.gitignore b/.gitignore index e97d5978..a64e3986 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ __pycache__/ *.pyzw *.pyzwz *.delete_me + +# MAC OS +*.DS_Store diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 0a756ace..2f60ead4 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -17,90 +17,115 @@ Note: `2025-06-07`: In order to make the best and quickly use of the tool in the - However, we provide a [PEP 751](https://peps.python.org/pep-0751/) `pylock.toml`, so don't feel forced to use uv - You can use beman-tidy as a pre-commit hook or install it on your system using `pipx` - ```console - $ uv build - $ pipx install path/to/wheel - ``` +```shell +$ uv build +$ pipx install path/to/wheel +``` + +

+beman-tidy: Full example - build and install + +```shell +$ uv build +Building source distribution... +Building wheel from source distribution... +Successfully built dist/beman_tidy-0.1.0.tar.gz +Successfully built dist/beman_tidy-0.1.0-py3-none-any.whl + +$ pipx install dist/beman_tidy-0.1.0-py3-none-any.whl --force +Installing to existing venv 'beman-tidy' + installed package beman-tidy 0.1.0, installed using Python 3.13.4 + These apps are now globally available + - beman-tidy +... +You will need to open a new terminal or re-login for the PATH changes to take effect. Alternatively, you can source your shell's config file with e.g. 'source ~/.bashrc'. + +$ beman-tidy --help +usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path +... +``` + +
## Usage * Display help: - ```console - $ uv run beman-tidy --help - usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path +```shell +$ uv run beman-tidy --help +usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path - positional arguments: - repo_path path to the repository to check +positional arguments: + repo_path path to the repository to check - optional arguments: - -h, --help show this help message and exit - --fix-inplace, --no-fix-inplace - Try to automatically fix found issues (default: False) - --verbose, --no-verbose - print verbose output for each check (default: False) - --checks CHECKS array of checks to run - ``` +optional arguments: + -h, --help show this help message and exit + --fix-inplace, --no-fix-inplace + Try to automatically fix found issues (default: False) + --verbose, --no-verbose + print verbose output for each check (default: False) + --checks CHECKS array of checks to run +``` * Run beman-tidy on the exemplar repository **(default: dry-run mode)** - ```shell - $ uv run beman-tidy path/to/exemplar - # non-verbose mode - Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). +```shell +$ uv run beman-tidy path/to/exemplar +# non-verbose mode +Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). - Coverage: 66.67% (2/3 checks passed). +Coverage: 66.67% (2/3 checks passed). - # verbose mode - no errors - $ ./beman-tidy /path/to/exemplar --verbose - beman-tidy pipeline started ... +# verbose mode - no errors +$ uv run beman-tidy /path/to/exemplar --verbose +beman-tidy pipeline started ... - Running check [RECOMMENDATION][README.TITLE] ... - [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. - check [RECOMMENDATION][README.TITLE] ... FAILED + Running check [RECOMMENDATION][README.TITLE] ... + [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. + check [RECOMMENDATION][README.TITLE] ... FAILED - Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED + Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED - Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED - beman-tidy pipeline finished. + beman-tidy pipeline finished. - Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). + Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). - Coverage: 66.67% (2/3 checks passed). - ``` +Coverage: 66.67% (2/3 checks passed). +``` - Run beman-tidy in verbose mode - ```console - $ ./beman-tidy /path/to/exemplar --verbose - beman-tidy pipeline started ... +```shell +$ uv run /path/to/exemplar --verbose +beman-tidy pipeline started ... - Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED +Running check [RECOMMENDATION][README.TITLE] ... + check [RECOMMENDATION][README.TITLE] ... PASSED - Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED +Running check [RECOMMENDATION][README.BADGES] ... + check [RECOMMENDATION][README.BADGES] ... PASSED - Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED - beman-tidy pipeline finished. +beman-tidy pipeline finished. - Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). +Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). - Coverage: 100.0% (3/3 checks passed). - ``` +Coverage: 100.0% (3/3 checks passed). +``` * Run beman-tidy on the exemplar repository (fix issues in-place): - ```console - $ uv run beman-tidy path/to/exemplar --fix-inplace --verbose - ``` +```shell +$ uv run beman-tidy path/to/exemplar --fix-inplace --verbose +``` ## beman-tidy Development diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 9342cf06..3cb62042 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -34,13 +34,11 @@ Limitations: ## Linting -Run the linter: +Run the linter on the beman-tidy's codebase: ```shell -# Run the linter - dry run. -$ make lint -# Run the linter - fix issues. -$ make lint-fix +$ uv run ruff check --diff +$ uv run ruff check --fix ``` ## Testing @@ -50,25 +48,22 @@ $ make lint-fix Run the tests: ```shell -$ make install-dev -pip3 install -r requirements-dev.txt -...q -$ make test -Running tests... -python3 -m pytest tests/ -v -========================================================================================================= test session starts ========================================================================================================= -platform darwin -- Python 3.9.6, pytest-8.4.0, pluggy-1.6.0 -- /Library/Developer/CommandLineTools/usr/bin/python3 +$ uv run pytest -v +================================================================================================================ test session starts ================================================================================================================ +platform darwin -- Python 3.14.0b2, pytest-8.4.0, pluggy-1.6.0 -- /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy/.venv/bin/python cachedir: .pytest_cache rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy -collected 3 items - -tests/beman_standard/readme/test_readme.py::test__README_TITLE__valid PASSED [ 33%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__invalid PASSED [ 66%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__fix_invalid PASSED [100%] - -========================================================================================================== 3 passed in 0.08s ========================================================================================================== +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_invalid 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_invalid SKIPPED (NOT implemented) [100%] +=========================================================================================================== 5 passed, 1 skipped in 0.07s ============================================================================================================ ``` ### Writing Tests diff --git a/tools/beman-tidy/pyproject.toml b/tools/beman-tidy/pyproject.toml index b2a78059..40da3257 100644 --- a/tools/beman-tidy/pyproject.toml +++ b/tools/beman-tidy/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "beman-tidy" version = "0.1.0" -description = "Add your description here" +description = "The Codebase Bemanification Tool" readme = "README.md" requires-python = ">=3.13" authors = [{ name = "Darius Neațu", email = "neatudarius@gmail.com" }] diff --git a/tools/beman-tidy/tests/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/beman_standard/readme/conftest.py index 55e9d206..e3acbb06 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/beman_standard/readme/conftest.py @@ -26,10 +26,10 @@ def invalid_readme_path(test_data_dir): @pytest.fixture(autouse=True) -def repo_info(mock_repo_info): +def repo_info(mock_repo_info): # noqa: F811 return mock_repo_info @pytest.fixture -def beman_standard_check_config(mock_beman_standard_check_config): +def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 return mock_beman_standard_check_config From 492c8ec650afba594956d140e0c66f72ded83048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 03:29:00 +0300 Subject: [PATCH 193/371] [beman-tidy] beman-tidy: remove unused Python deps (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Authored-by: Darius Neațu --- tools/beman-tidy/README.md | 2 +- tools/beman-tidy/docs/dev-guide.md | 12 ++++- tools/beman-tidy/pylock.toml | 57 ---------------------- tools/beman-tidy/pyproject.toml | 2 - tools/beman-tidy/uv.lock | 77 ------------------------------ 5 files changed, 12 insertions(+), 138 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 2f60ead4..2e4e6815 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -32,7 +32,7 @@ Building wheel from source distribution... Successfully built dist/beman_tidy-0.1.0.tar.gz Successfully built dist/beman_tidy-0.1.0-py3-none-any.whl -$ pipx install dist/beman_tidy-0.1.0-py3-none-any.whl --force +$ pipx install dist/beman_tidy-0.1.0-py3-none-any.whl Installing to existing venv 'beman-tidy' installed package beman-tidy 0.1.0, installed using Python 3.13.4 These apps are now globally available diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 3cb62042..228adb64 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -48,7 +48,7 @@ $ uv run ruff check --fix Run the tests: ```shell -$ uv run pytest -v +$ uv run pytest ================================================================================================================ test session starts ================================================================================================================ platform darwin -- Python 3.14.0b2, pytest-8.4.0, pluggy-1.6.0 -- /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy/.venv/bin/python cachedir: .pytest_cache @@ -84,3 +84,13 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI * `valid`: The test case for the valid case. * `invalid`: The test case for the invalid case. * `fix_invalid`: 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. + + +## Changing dependencies + +* Add / update the dependency to the `pyproject.toml` file. +* Run `uv clean` to make sure the dependencies are updated. +* Run `uv sync && uv export -o pylock.toml` to update the dependencies. +* Run `uv build` to build the wheel. +* Run `uv run beman-tidy --help` to check if the new dependency is available. +* Commit the changes from `pyproject.toml`, `pylock.toml` and `uv.lock`. diff --git a/tools/beman-tidy/pylock.toml b/tools/beman-tidy/pylock.toml index 53a6e4a1..918baaa2 100644 --- a/tools/beman-tidy/pylock.toml +++ b/tools/beman-tidy/pylock.toml @@ -8,35 +8,6 @@ requires-python = ">=3.13" name = "beman-tidy" directory = { path = ".", editable = true } -[[packages]] -name = "certifi" -version = "2025.6.15" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", upload-time = 2025-06-15T02:45:51Z, size = 158753, hashes = { sha256 = "d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", upload-time = 2025-06-15T02:45:49Z, size = 157650, hashes = { sha256 = "2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057" } }] - -[[packages]] -name = "charset-normalizer" -version = "3.4.2" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", upload-time = 2025-05-02T08:34:42Z, size = 126367, hashes = { sha256 = "5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63" } } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", upload-time = 2025-05-02T08:32:56Z, size = 199622, hashes = { sha256 = "926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0" } }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-05-02T08:32:58Z, size = 143435, hashes = { sha256 = "eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf" } }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-05-02T08:33:00Z, size = 153653, hashes = { sha256 = "3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e" } }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-05-02T08:33:02Z, size = 146231, hashes = { sha256 = "98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1" } }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-05-02T08:33:04Z, size = 148243, hashes = { sha256 = "6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c" } }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", upload-time = 2025-05-02T08:33:06Z, size = 150442, hashes = { sha256 = "e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691" } }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", upload-time = 2025-05-02T08:33:08Z, size = 145147, hashes = { sha256 = "1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0" } }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", upload-time = 2025-05-02T08:33:09Z, size = 153057, hashes = { sha256 = "ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b" } }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", upload-time = 2025-05-02T08:33:11Z, size = 156454, hashes = { sha256 = "32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff" } }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", upload-time = 2025-05-02T08:33:13Z, size = 154174, hashes = { sha256 = "289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b" } }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", upload-time = 2025-05-02T08:33:15Z, size = 149166, hashes = { sha256 = "4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148" } }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", upload-time = 2025-05-02T08:33:17Z, size = 98064, hashes = { sha256 = "aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7" } }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", upload-time = 2025-05-02T08:33:18Z, size = 105641, hashes = { sha256 = "aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980" } }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", upload-time = 2025-05-02T08:34:40Z, size = 52626, hashes = { sha256 = "7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0" } }, -] - [[packages]] name = "colorama" version = "0.4.6" @@ -59,13 +30,6 @@ index = "https://pypi.org/simple" sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", upload-time = 2025-01-02T07:32:43Z, size = 214196, hashes = { sha256 = "c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269" } } wheels = [{ name = "gitpython-3.1.44-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", upload-time = 2025-01-02T07:32:40Z, size = 207599, hashes = { sha256 = "9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110" } }] -[[packages]] -name = "idna" -version = "3.10" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", upload-time = 2024-09-15T18:07:39Z, size = 190490, hashes = { sha256 = "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", upload-time = 2024-09-15T18:07:37Z, size = 70442, hashes = { sha256 = "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" } }] - [[packages]] name = "iniconfig" version = "2.1.0" @@ -73,13 +37,6 @@ index = "https://pypi.org/simple" sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", upload-time = 2025-03-19T20:09:59Z, size = 4793, hashes = { sha256 = "3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7" } } wheels = [{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", upload-time = 2025-03-19T20:10:01Z, size = 6050, hashes = { sha256 = "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" } }] -[[packages]] -name = "markdown" -version = "3.4.4" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/87/2a/62841f4fb1fef5fa015ded48d02401cd95643ca03b6760b29437b62a04a4/Markdown-3.4.4.tar.gz", upload-time = 2023-07-25T15:13:45Z, size = 324459, hashes = { sha256 = "225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6" } } -wheels = [{ name = "markdown-3.4.4-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/1a/b5/228c1cdcfe138f1a8e01ab1b54284c8b83735476cb22b6ba251656ed13ad/Markdown-3.4.4-py3-none-any.whl", upload-time = 2023-07-25T15:13:43Z, size = 94174, hashes = { sha256 = "a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941" } }] - [[packages]] name = "packaging" version = "25.0" @@ -125,13 +82,6 @@ wheels = [ { name = "pyyaml-6.0.2-cp313-cp313-win_amd64.whl", url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", upload-time = 2024-08-06T20:33:04Z, size = 156446, hashes = { sha256 = "8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563" } }, ] -[[packages]] -name = "requests" -version = "2.32.3" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", upload-time = 2024-05-29T15:37:49Z, size = 131218, hashes = { sha256 = "55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", upload-time = 2024-05-29T15:37:47Z, size = 64928, hashes = { sha256 = "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" } }] - [[packages]] name = "ruff" version = "0.11.13" @@ -163,10 +113,3 @@ version = "5.0.2" index = "https://pypi.org/simple" sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", upload-time = 2025-01-02T07:14:40Z, size = 22329, hashes = { sha256 = "26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5" } } wheels = [{ url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", upload-time = 2025-01-02T07:14:38Z, size = 24303, hashes = { sha256 = "b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e" } }] - -[[packages]] -name = "urllib3" -version = "2.4.0" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", upload-time = 2025-04-10T15:23:39Z, size = 390672, hashes = { sha256 = "414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", upload-time = 2025-04-10T15:23:37Z, size = 128680, hashes = { sha256 = "4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813" } }] diff --git a/tools/beman-tidy/pyproject.toml b/tools/beman-tidy/pyproject.toml index 40da3257..26618a5a 100644 --- a/tools/beman-tidy/pyproject.toml +++ b/tools/beman-tidy/pyproject.toml @@ -8,9 +8,7 @@ authors = [{ name = "Darius Neațu", email = "neatudarius@gmail.com" }] maintainers = [{ name = "Rishyak", email = "hello@rishyak.com" }] dependencies = [ "gitpython==3.1.44", - "markdown==3.4.4", "pyyaml==6.0.2", - "requests==2.32.3", ] [build-system] diff --git a/tools/beman-tidy/uv.lock b/tools/beman-tidy/uv.lock index a4ad32b9..11cc1cf2 100644 --- a/tools/beman-tidy/uv.lock +++ b/tools/beman-tidy/uv.lock @@ -8,9 +8,7 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "gitpython" }, - { name = "markdown" }, { name = "pyyaml" }, - { name = "requests" }, ] [package.dev-dependencies] @@ -22,9 +20,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "gitpython", specifier = "==3.1.44" }, - { name = "markdown", specifier = "==3.4.4" }, { name = "pyyaml", specifier = "==6.0.2" }, - { name = "requests", specifier = "==2.32.3" }, ] [package.metadata.requires-dev] @@ -33,37 +29,6 @@ dev = [ { name = "ruff", specifier = ">=0.11.13" }, ] -[[package]] -name = "certifi" -version = "2025.6.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -97,15 +62,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599, upload-time = "2025-01-02T07:32:40.731Z" }, ] -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - [[package]] name = "iniconfig" version = "2.1.0" @@ -115,15 +71,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] -[[package]] -name = "markdown" -version = "3.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/2a/62841f4fb1fef5fa015ded48d02401cd95643ca03b6760b29437b62a04a4/Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6", size = 324459, upload-time = "2023-07-25T15:13:45.311Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/b5/228c1cdcfe138f1a8e01ab1b54284c8b83735476cb22b6ba251656ed13ad/Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941", size = 94174, upload-time = "2023-07-25T15:13:43.124Z" }, -] - [[package]] name = "packaging" version = "25.0" @@ -184,21 +131,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, ] -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, -] - [[package]] name = "ruff" version = "0.11.13" @@ -232,12 +164,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532 wheels = [ { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, ] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] From 82634fc2d92fb9168fe1965e28b350919332eb80 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 23:05:18 -0400 Subject: [PATCH 194/371] chore(gitignore): add editor config files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index a64e3986..e5fda7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,7 @@ __pycache__/ # MAC OS *.DS_Store + +# editor files +.vscode/ +.idea/ From 75964b07cdef8e9bada0c883b3fec4ed45facc28 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 23:06:41 -0400 Subject: [PATCH 195/371] build: downgrade python version and sync deps --- tools/beman-tidy/.python-version | 2 +- tools/beman-tidy/pylock.toml | 11 ++++++++++- tools/beman-tidy/pyproject.toml | 7 ++----- tools/beman-tidy/uv.lock | 11 ++++++++++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/tools/beman-tidy/.python-version b/tools/beman-tidy/.python-version index 6324d401..e4fba218 100644 --- a/tools/beman-tidy/.python-version +++ b/tools/beman-tidy/.python-version @@ -1 +1 @@ -3.14 +3.12 diff --git a/tools/beman-tidy/pylock.toml b/tools/beman-tidy/pylock.toml index 918baaa2..8fb1d543 100644 --- a/tools/beman-tidy/pylock.toml +++ b/tools/beman-tidy/pylock.toml @@ -2,7 +2,7 @@ # uv export -o pylock.toml lock-version = "1.0" created-by = "uv" -requires-python = ">=3.13" +requires-python = ">=3.12" [[packages]] name = "beman-tidy" @@ -71,6 +71,15 @@ version = "6.0.2" index = "https://pypi.org/simple" sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", upload-time = 2024-08-06T20:33:50Z, size = 130631, hashes = { sha256 = "d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e" } } wheels = [ + { name = "pyyaml-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", upload-time = 2024-08-06T20:32:25Z, size = 183873, hashes = { sha256 = "c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab" } }, + { name = "pyyaml-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", upload-time = 2024-08-06T20:32:26Z, size = 173302, hashes = { sha256 = "ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725" } }, + { name = "pyyaml-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2024-08-06T20:32:28Z, size = 739154, hashes = { sha256 = "1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5" } }, + { name = "pyyaml-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2024-08-06T20:32:30Z, size = 766223, hashes = { sha256 = "9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425" } }, + { name = "pyyaml-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-08-06T20:32:31Z, size = 767542, hashes = { sha256 = "80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476" } }, + { name = "pyyaml-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", upload-time = 2024-08-06T20:32:37Z, size = 731164, hashes = { sha256 = "0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48" } }, + { name = "pyyaml-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", upload-time = 2024-08-06T20:32:38Z, size = 756611, hashes = { sha256 = "8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b" } }, + { name = "pyyaml-6.0.2-cp312-cp312-win32.whl", url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", upload-time = 2024-08-06T20:32:40Z, size = 140591, hashes = { sha256 = "ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4" } }, + { name = "pyyaml-6.0.2-cp312-cp312-win_amd64.whl", url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", upload-time = 2024-08-06T20:32:41Z, size = 156338, hashes = { sha256 = "7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8" } }, { name = "pyyaml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", upload-time = 2024-08-06T20:32:43Z, size = 181309, hashes = { sha256 = "efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba" } }, { name = "pyyaml-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", upload-time = 2024-08-06T20:32:44Z, size = 171679, hashes = { sha256 = "50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1" } }, { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2024-08-06T20:32:46Z, size = 733428, hashes = { sha256 = "0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133" } }, diff --git a/tools/beman-tidy/pyproject.toml b/tools/beman-tidy/pyproject.toml index 26618a5a..36d77c88 100644 --- a/tools/beman-tidy/pyproject.toml +++ b/tools/beman-tidy/pyproject.toml @@ -3,13 +3,10 @@ name = "beman-tidy" version = "0.1.0" description = "The Codebase Bemanification Tool" readme = "README.md" -requires-python = ">=3.13" +requires-python = ">=3.12" authors = [{ name = "Darius Neațu", email = "neatudarius@gmail.com" }] maintainers = [{ name = "Rishyak", email = "hello@rishyak.com" }] -dependencies = [ - "gitpython==3.1.44", - "pyyaml==6.0.2", -] +dependencies = ["gitpython==3.1.44", "pyyaml==6.0.2"] [build-system] requires = ["flit_core >=3.2,<4"] diff --git a/tools/beman-tidy/uv.lock b/tools/beman-tidy/uv.lock index 11cc1cf2..da07ff4a 100644 --- a/tools/beman-tidy/uv.lock +++ b/tools/beman-tidy/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 2 -requires-python = ">=3.13" +requires-python = ">=3.12" [[package]] name = "beman-tidy" @@ -120,6 +120,15 @@ version = "6.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, From 4b34b53ff7f271b9060e7ad13768b2b590e643e2 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 23:36:49 -0400 Subject: [PATCH 196/371] fix: adopt src/ layout to include lib/ subpackage in distribution - Move code under beman_tidy/ (including lib/) - This aligns with PyPA's recommended flat layout, and ensures your lib/ subpackage is bundled in the wheel. - See: https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/ --- tools/beman-tidy/{ => beman_tidy}/.beman-standard.yml | 0 tools/beman-tidy/{ => beman_tidy}/__init__.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/__init__.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/checks/__init__.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/checks/base/__init__.py | 0 .../beman-tidy/{ => beman_tidy}/lib/checks/base/base_check.py | 0 .../{ => beman_tidy}/lib/checks/base/directory_base_check.py | 0 .../{ => beman_tidy}/lib/checks/base/file_base_check.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/__init__.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/cmake.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/cpp.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/directory.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/file.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/general.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/license.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/readme.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/release.py | 0 .../{ => beman_tidy}/lib/checks/beman_standard/toplevel.py | 0 .../beman-tidy/{ => beman_tidy}/lib/checks/system/__init__.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/checks/system/git.py | 0 .../beman-tidy/{ => beman_tidy}/lib/checks/system/registry.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/pipeline.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/utils/__init__.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/utils/git.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/utils/string.py | 0 tools/beman-tidy/{ => beman_tidy}/lib/utils/terminal.py | 0 tools/beman-tidy/{beman_tidy.py => beman_tidy/main.py} | 4 ++-- tools/beman-tidy/pyproject.toml | 2 +- tools/beman-tidy/tests/beman_standard/readme/test_readme.py | 2 +- tools/beman-tidy/tests/utils/conftest.py | 2 +- 30 files changed, 5 insertions(+), 5 deletions(-) rename tools/beman-tidy/{ => beman_tidy}/.beman-standard.yml (100%) rename tools/beman-tidy/{ => beman_tidy}/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/base/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/base/base_check.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/base/directory_base_check.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/base/file_base_check.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/cmake.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/cpp.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/directory.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/file.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/general.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/license.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/readme.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/release.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/beman_standard/toplevel.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/system/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/system/git.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/checks/system/registry.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/pipeline.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/utils/__init__.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/utils/git.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/utils/string.py (100%) rename tools/beman-tidy/{ => beman_tidy}/lib/utils/terminal.py (100%) rename tools/beman-tidy/{beman_tidy.py => beman_tidy/main.py} (91%) diff --git a/tools/beman-tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml similarity index 100% rename from tools/beman-tidy/.beman-standard.yml rename to tools/beman-tidy/beman_tidy/.beman-standard.yml diff --git a/tools/beman-tidy/__init__.py b/tools/beman-tidy/beman_tidy/__init__.py similarity index 100% rename from tools/beman-tidy/__init__.py rename to tools/beman-tidy/beman_tidy/__init__.py diff --git a/tools/beman-tidy/lib/__init__.py b/tools/beman-tidy/beman_tidy/lib/__init__.py similarity index 100% rename from tools/beman-tidy/lib/__init__.py rename to tools/beman-tidy/beman_tidy/lib/__init__.py diff --git a/tools/beman-tidy/lib/checks/__init__.py b/tools/beman-tidy/beman_tidy/lib/checks/__init__.py similarity index 100% rename from tools/beman-tidy/lib/checks/__init__.py rename to tools/beman-tidy/beman_tidy/lib/checks/__init__.py diff --git a/tools/beman-tidy/lib/checks/base/__init__.py b/tools/beman-tidy/beman_tidy/lib/checks/base/__init__.py similarity index 100% rename from tools/beman-tidy/lib/checks/base/__init__.py rename to tools/beman-tidy/beman_tidy/lib/checks/base/__init__.py diff --git a/tools/beman-tidy/lib/checks/base/base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py similarity index 100% rename from tools/beman-tidy/lib/checks/base/base_check.py rename to tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py diff --git a/tools/beman-tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py similarity index 100% rename from tools/beman-tidy/lib/checks/base/directory_base_check.py rename to tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py diff --git a/tools/beman-tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py similarity index 100% rename from tools/beman-tidy/lib/checks/base/file_base_check.py rename to tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/__init__.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/__init__.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/__init__.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/__init__.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/cmake.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/cpp.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/directory.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/file.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/general.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/general.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/license.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/readme.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/release.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py diff --git a/tools/beman-tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py similarity index 100% rename from tools/beman-tidy/lib/checks/beman_standard/toplevel.py rename to tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py diff --git a/tools/beman-tidy/lib/checks/system/__init__.py b/tools/beman-tidy/beman_tidy/lib/checks/system/__init__.py similarity index 100% rename from tools/beman-tidy/lib/checks/system/__init__.py rename to tools/beman-tidy/beman_tidy/lib/checks/system/__init__.py diff --git a/tools/beman-tidy/lib/checks/system/git.py b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py similarity index 100% rename from tools/beman-tidy/lib/checks/system/git.py rename to tools/beman-tidy/beman_tidy/lib/checks/system/git.py diff --git a/tools/beman-tidy/lib/checks/system/registry.py b/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py similarity index 100% rename from tools/beman-tidy/lib/checks/system/registry.py rename to tools/beman-tidy/beman_tidy/lib/checks/system/registry.py diff --git a/tools/beman-tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py similarity index 100% rename from tools/beman-tidy/lib/pipeline.py rename to tools/beman-tidy/beman_tidy/lib/pipeline.py diff --git a/tools/beman-tidy/lib/utils/__init__.py b/tools/beman-tidy/beman_tidy/lib/utils/__init__.py similarity index 100% rename from tools/beman-tidy/lib/utils/__init__.py rename to tools/beman-tidy/beman_tidy/lib/utils/__init__.py diff --git a/tools/beman-tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py similarity index 100% rename from tools/beman-tidy/lib/utils/git.py rename to tools/beman-tidy/beman_tidy/lib/utils/git.py diff --git a/tools/beman-tidy/lib/utils/string.py b/tools/beman-tidy/beman_tidy/lib/utils/string.py similarity index 100% rename from tools/beman-tidy/lib/utils/string.py rename to tools/beman-tidy/beman_tidy/lib/utils/string.py diff --git a/tools/beman-tidy/lib/utils/terminal.py b/tools/beman-tidy/beman_tidy/lib/utils/terminal.py similarity index 100% rename from tools/beman-tidy/lib/utils/terminal.py rename to tools/beman-tidy/beman_tidy/lib/utils/terminal.py diff --git a/tools/beman-tidy/beman_tidy.py b/tools/beman-tidy/beman_tidy/main.py similarity index 91% rename from tools/beman-tidy/beman_tidy.py rename to tools/beman-tidy/beman_tidy/main.py index dd9819e7..9c25c59e 100755 --- a/tools/beman-tidy/beman_tidy.py +++ b/tools/beman-tidy/beman_tidy/main.py @@ -4,8 +4,8 @@ import argparse import sys -from lib.utils.git import get_repo_info, load_beman_standard_config -from lib.pipeline import run_checks_pipeline +from beman_tidy.lib.utils.git import get_repo_info, load_beman_standard_config +from beman_tidy.lib.pipeline import run_checks_pipeline def parse_args(): diff --git a/tools/beman-tidy/pyproject.toml b/tools/beman-tidy/pyproject.toml index 36d77c88..0378288a 100644 --- a/tools/beman-tidy/pyproject.toml +++ b/tools/beman-tidy/pyproject.toml @@ -16,7 +16,7 @@ build-backend = "flit_core.buildapi" dev = ["pytest>=8.4.0", "ruff>=0.11.13"] [project.scripts] -beman-tidy = "beman_tidy:main" +beman-tidy = "beman_tidy.main:main" [tool.pytest.ini_options] addopts = "-v" diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py index 92e2b6f0..16d8aae4 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -6,7 +6,7 @@ from tests.utils.file_testcase_runners import file_testcases_run_valid, file_testcases_run_invalid, file_testcases_run_fix_invalid # Actual tested checks. -from lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck +from beman_tidy.lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck def test__README_TITLE__valid(repo_info, beman_standard_check_config): diff --git a/tools/beman-tidy/tests/utils/conftest.py b/tools/beman-tidy/tests/utils/conftest.py index 45cb4060..87e4fb85 100644 --- a/tools/beman-tidy/tests/utils/conftest.py +++ b/tools/beman-tidy/tests/utils/conftest.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import pytest -from lib.utils.git import load_beman_standard_config +from beman_tidy.lib.utils.git import load_beman_standard_config @pytest.fixture From c95e471278b4b05fbc59920766d9065b743f8aa9 Mon Sep 17 00:00:00 2001 From: rishyak Date: Tue, 17 Jun 2025 23:37:17 -0400 Subject: [PATCH 197/371] docs(dev guide): update dependency management steps --- tools/beman-tidy/docs/dev-guide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 228adb64..53f8f8a8 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -90,7 +90,8 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI * Add / update the dependency to the `pyproject.toml` file. * Run `uv clean` to make sure the dependencies are updated. -* Run `uv sync && uv export -o pylock.toml` to update the dependencies. +* Run `uv sync` to update the uv lockfile +* Run `uv export -o pylock.toml` to update `pylock.toml` * Run `uv build` to build the wheel. * Run `uv run beman-tidy --help` to check if the new dependency is available. * Commit the changes from `pyproject.toml`, `pylock.toml` and `uv.lock`. From e27ae4950a83b9d6330cab8276636ee154991442 Mon Sep 17 00:00:00 2001 From: rishyak Date: Wed, 18 Jun 2025 00:53:33 -0400 Subject: [PATCH 198/371] chore: rename main.py to cli.py --- tools/beman-tidy/beman_tidy/{main.py => cli.py} | 0 tools/beman-tidy/pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tools/beman-tidy/beman_tidy/{main.py => cli.py} (100%) diff --git a/tools/beman-tidy/beman_tidy/main.py b/tools/beman-tidy/beman_tidy/cli.py similarity index 100% rename from tools/beman-tidy/beman_tidy/main.py rename to tools/beman-tidy/beman_tidy/cli.py diff --git a/tools/beman-tidy/pyproject.toml b/tools/beman-tidy/pyproject.toml index 0378288a..fdc1d372 100644 --- a/tools/beman-tidy/pyproject.toml +++ b/tools/beman-tidy/pyproject.toml @@ -16,7 +16,7 @@ build-backend = "flit_core.buildapi" dev = ["pytest>=8.4.0", "ruff>=0.11.13"] [project.scripts] -beman-tidy = "beman_tidy.main:main" +beman-tidy = "beman_tidy.cli:main" [tool.pytest.ini_options] addopts = "-v" From b56e87e07452518a030a0c79838a07fa87c56203 Mon Sep 17 00:00:00 2001 From: rishyak Date: Wed, 18 Jun 2025 00:54:54 -0400 Subject: [PATCH 199/371] chore: add @rishyak to codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4db7c078..67d9e9ba 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @ednolan @neatudarius @wusatosi @bemanproject/core-reviewers +* @ednolan @neatudarius @rishyak @wusatosi @bemanproject/core-reviewers From cc1448593c81f3f278dc8569c24c6f088ec265a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 08:21:29 +0300 Subject: [PATCH 200/371] [beman-tidy] exclude build artifacts --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index e5fda7e3..a7236dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,8 @@ __pycache__/ # editor files .vscode/ .idea/ + +# Python +infra.egg-info +beman_tidy.egg-info +*.egg-info From 0e29ce97ae2474ee3c79a336f4b99e8a4ba7619b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 08:27:40 +0300 Subject: [PATCH 201/371] Exclude more build artifacts --- .gitignore | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e5fda7e3..7389e9e9 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,14 @@ __pycache__/ # MAC OS *.DS_Store -# editor files +# Editor files .vscode/ .idea/ + +# Build directories +infra.egg-info/ +beman_tidy.egg-info/ +*.egg-info/ +build/ +dist/ + From ffc32a058b5ddb07fbd8ad6b1dd1de44993898b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 16 Jun 2025 16:19:30 +0300 Subject: [PATCH 202/371] beman-tidy: add check - README.LIBRARY_STATUS --- .../lib/checks/beman_standard/readme.py | 26 +++++++++++++- tools/beman-tidy/beman_tidy/lib/pipeline.py | 2 +- .../data/invalid/invalid-status-line-v1.md | 14 ++++++++ .../data/invalid/invalid-status-line-v2.md | 15 ++++++++ .../data/invalid/invalid-status-line-v3.md | 18 ++++++++++ .../beman_standard/readme/test_readme.py | 34 ++++++++++++++++++- 6 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md create mode 100644 tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 33ec4d19..535b64b2 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -76,4 +76,28 @@ def fix(self): # TODO README.IMPLEMENTS -# TODO 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) + + def check(self): + """ + self.config["values"] contains a fixed set of Beman library statuses. + """ + statuses = self.config["values"] + assert len(statuses) == len(self.beman_library_maturity_model) + + # Check if at least one of the required status values is present. + status_count = len( + [status for status in statuses if self.has_content(status)]) + if status_count != 1: + self.log( + f"The file '{self.path}' does not contain exactly one of the required statuses from {statuses}") + return False + + return True + + def fix(self): + # TODO: Implement the fix. + pass diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index fc51c859..f63f6e28 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -13,7 +13,7 @@ # from .checks.beman_standard.file import # from .checks.beman_standard.general import # from .checks.beman_standard.license import -from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck # noqa: F401 +from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck # noqa: F401 # from .checks.beman_standard.release import # from .checks.beman_standard.toplevel import diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md new file mode 100644 index 00000000..aa46bddb --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md @@ -0,0 +1,14 @@ +## 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) + +**Purpose**: `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. + +This is NOT a valid README.md according to the Beman Standard: the library status is not properly formatted. diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md new file mode 100644 index 00000000..6d3f668f --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v2.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) + +**Purpose**: `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) + +This is NOT a valid README.md according to the Beman Standard: the library status line has typos. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md new file mode 100644 index 00000000..af1629a1 --- /dev/null +++ b/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md @@ -0,0 +1,18 @@ +# 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) + +**Purpose**: `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), + +This is NOT a valid README.md according to the Beman Standard: the library status is duplicated. + diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py index 16d8aae4..6f0e39b3 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/beman_standard/readme/test_readme.py @@ -6,7 +6,7 @@ from tests.utils.file_testcase_runners import file_testcases_run_valid, file_testcases_run_invalid, file_testcases_run_fix_invalid # Actual tested checks. -from beman_tidy.lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck +from beman_tidy.lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck def test__README_TITLE__valid(repo_info, beman_standard_check_config): @@ -83,3 +83,35 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): """Test that the fix method corrects an invalid README.md badges""" pass + + +def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config, valid_readme_path): + """Test that a valid README.md library status passes the check""" + valid_readme_paths = [ + Path("tests/beman_standard/readme/data/valid/README-v1.md"), + Path("tests/beman_standard/readme/data/valid/README-v2.md"), + Path("tests/beman_standard/readme/data/valid/README-v3.md"), + Path("tests/beman_standard/readme/data/valid/README-v4.md"), + ] + + file_testcases_run_valid(valid_readme_paths, ReadmeLibraryStatusCheck, + 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""" + invalid_readme_paths = [ + Path("tests/beman_standard/readme/data/invalid/invalid.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v1.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v2.md"), + Path("tests/beman_standard/readme/data/invalid/invalid-status-line-v3.md"), + ] + + file_testcases_run_invalid(invalid_readme_paths, ReadmeLibraryStatusCheck, + repo_info, beman_standard_check_config) + + +@pytest.mark.skip(reason="NOT implemented") +def test__README_LIBRARY_STATUS__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): + """Test that the fix method corrects an invalid README.md library status""" + pass From d869b650c98bc0e482243fe04b2cda1d204cde8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 08:46:08 +0300 Subject: [PATCH 203/371] beman-tidy: tests/ subtree should mirror beman_tidy subtree --- tools/beman-tidy/docs/dev-guide.md | 42 +++++++++++++---- .../tests/{beman_standard => lib}/__init__.py | 0 .../readme => lib/checks}/__init__.py | 0 .../lib/checks/beman_standard/__init__.py | 0 .../checks/beman_standard/readme/__init__.py | 0 .../checks}/beman_standard/readme/conftest.py | 0 .../readme/data/invalid/invalid-badge-v1.md | 0 .../readme/data/invalid/invalid-badge-v2.md | 0 .../readme/data/invalid/invalid-badge-v3.md | 0 .../readme/data/invalid/invalid-title-v1.md | 0 .../readme/data/invalid/invalid-title-v2.md | 0 .../readme/data/invalid/invalid-title-v3.md | 0 .../readme/data/invalid/invalid-title-v4.md | 0 .../readme/data/invalid/invalid.md | 0 .../readme/data/valid/README-v1.md | 0 .../readme/data/valid/README-v2.md | 0 .../readme/data/valid/README-v3.md | 0 .../readme/data/valid/README-v4.md | 0 .../beman_standard/readme/test_readme.py | 45 ++++++++++--------- 19 files changed, 58 insertions(+), 29 deletions(-) rename tools/beman-tidy/tests/{beman_standard => lib}/__init__.py (100%) rename tools/beman-tidy/tests/{beman_standard/readme => lib/checks}/__init__.py (100%) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/__init__.py rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/conftest.py (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-badge-v1.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-badge-v2.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-badge-v3.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-title-v1.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-title-v2.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-title-v3.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid-title-v4.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/invalid/invalid.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/valid/README-v1.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/valid/README-v2.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/valid/README-v3.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/data/valid/README-v4.md (100%) rename tools/beman-tidy/tests/{ => lib/checks}/beman_standard/readme/test_readme.py (61%) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 53f8f8a8..434edbc4 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -22,16 +22,42 @@ Limitations: ## Tree structure -* `beman-tidy`: A Python script that is used to check and apply the Beman Standard to a repository. -* `.beman-standard.yml`: Stable version of the standard; the tool does not fetch the latest unstable version of the standard. -* `lib/`: The library for the beman-tidy tool (e.g, checks, utils, etc.). - * `lib/checks/beman_standard/`: Direct implementation of the checks from the standard (e.g, `lib/checks/beman_standard/readme.py` is the implementation of the `README.md` checks). - * `lib/checks/base/`: Base classes for the checks - not to be used directly. - * `lib/pipeline.py`: The pipeline for the `beman-tidy` tool. -* `tests/`: The tests for the beman-tidy tool. - * Structure is similar to the `lib/` directory. +```shell +$ ls -l +total 104 +-rw-r--r-- 1 dariusn staff 4257 Jun 18 08:15 README.md +drwxr-xr-x 7 dariusn staff 224 Jun 18 08:29 beman_tidy +drwxr-xr-x 3 dariusn staff 96 Jun 18 08:25 docs +-rw-r--r-- 1 dariusn staff 19490 Jun 18 08:15 pylock.toml +-rw-r--r-- 1 dariusn staff 582 Jun 18 08:15 pyproject.toml +drwxr-xr-x 7 dariusn staff 224 Jun 18 08:29 tests +-rw-r--r-- 1 dariusn staff 18975 Jun 18 08:15 uv.lock +``` + +* `beman-tidy`: All production code. +* `docs/`: The internal documentation for the `beman-tidy` tool. +* `README.md`: The public documentation for the `beman-tidy` tool. +* `beman_tidy/`: The package for the `beman-tidy` tool. + * `beman_tidy/cli.py`: The CLI for the `beman-tidy` tool. + * `beman_tidy/lib/`: The library for the `beman-tidy` tool. + * `beman_tidy/lib/checks/`: The checks for the `beman-tidy` tool. + * `beman_tidy/lib/utils/`: The utility functions for the `beman-tidy` tool. + * `beman_tidy/lib/pipeline.py`: The pipeline for the `beman-tidy` tool. + * `beman_tidy/.beman-standard.yml`: Stable version of the standard; the tool does not fetch the latest unstable version of the standard. +* `tests/`: The tests for the `beman-tidy` tool. + * Structure is similar to the `beman_tidy/` directory. * `pytest` is used for testing. +## Adding a new check + +* Add the check to the `beman_tidy/lib/checks/beman_standard/` directory. +* Add the check to the `beman_tidy/lib/pipeline.py` file. +* Add the check to the `tests/beman_standard/` directory. +* Add the check to the `docs/dev-guide.md` file. +* Add the check to the `README.md` file. + +Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). + ## Linting Run the linter on the beman-tidy's codebase: diff --git a/tools/beman-tidy/tests/beman_standard/__init__.py b/tools/beman-tidy/tests/lib/__init__.py similarity index 100% rename from tools/beman-tidy/tests/beman_standard/__init__.py rename to tools/beman-tidy/tests/lib/__init__.py diff --git a/tools/beman-tidy/tests/beman_standard/readme/__init__.py b/tools/beman-tidy/tests/lib/checks/__init__.py similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/__init__.py rename to tools/beman-tidy/tests/lib/checks/__init__.py diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/conftest.py rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v1.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v2.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-badge-v3.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v1.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v2.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v3.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid-title-v4.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/invalid/invalid.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v1.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v2.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v3.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md similarity index 100% rename from tools/beman-tidy/tests/beman_standard/readme/data/valid/README-v4.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md diff --git a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py similarity index 61% rename from tools/beman-tidy/tests/beman_standard/readme/test_readme.py rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 16d8aae4..cdf841b3 100644 --- a/tools/beman-tidy/tests/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -8,18 +8,21 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck +test_data_prefix = "tests/lib/checks/beman_standard/readme/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" def test__README_TITLE__valid(repo_info, beman_standard_check_config): """Test that a valid README.md title passes the check""" valid_readme_paths = [ # Title: # beman.exemplar: A Beman Library Exemplar - Path("tests/beman_standard/readme/data/valid/README-v1.md"), + Path(f"{valid_prefix}/README-v1.md"), # Title: # beman.exemplar: Another Beman Library - Path("tests/beman_standard/readme/data/valid/README-v2.md"), + Path(f"{valid_prefix}/README-v2.md"), # Title: # beman.exemplar: Awesome Beman Library - Path("tests/beman_standard/readme/data/valid/README-v3.md"), + Path(f"{valid_prefix}/README-v3.md"), # Title: # beman.exemplar: The Most Awesome Beman Library - Path("tests/beman_standard/readme/data/valid/README-v4.md"), + Path(f"{valid_prefix}/README-v4.md"), ] file_testcases_run_valid(valid_readme_paths, ReadmeTitleCheck, @@ -29,11 +32,11 @@ def test__README_TITLE__valid(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 = [ - Path("tests/beman_standard/readme/data/invalid/invalid.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v1.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v2.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v3.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v4.md"), + Path(f"{invalid_prefix}/invalid.md"), + 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"), ] file_testcases_run_invalid(invalid_readme_paths, ReadmeTitleCheck, @@ -43,10 +46,10 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): """Test that the fix method corrects an invalid README.md title""" invalid_readme_paths = [ - Path("tests/beman_standard/readme/data/invalid/invalid-title-v1.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v2.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v3.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-title-v4.md"), + 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"), ] file_testcases_run_fix_invalid( @@ -56,10 +59,10 @@ def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_readme_path): """Test that a valid README.md badges passes the check""" valid_readme_paths = [ - Path("tests/beman_standard/readme/data/valid/README-v1.md"), - Path("tests/beman_standard/readme/data/valid/README-v2.md"), - Path("tests/beman_standard/readme/data/valid/README-v3.md"), - Path("tests/beman_standard/readme/data/valid/README-v4.md"), + 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"), ] file_testcases_run_valid(valid_readme_paths, ReadmeBadgesCheck, @@ -69,10 +72,10 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_rea def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid_readme_path): """Test that an invalid README.md badges fails the check""" invalid_readme_paths = [ - Path("tests/beman_standard/readme/data/invalid/invalid.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-badge-v1.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-badge-v2.md"), - Path("tests/beman_standard/readme/data/invalid/invalid-badge-v3.md"), + Path(f"{invalid_prefix}/invalid.md"), + Path(f"{invalid_prefix}/invalid-badge-v1.md"), + Path(f"{invalid_prefix}/invalid-badge-v2.md"), + Path(f"{invalid_prefix}/invalid-badge-v3.md"), ] file_testcases_run_invalid(invalid_readme_paths, ReadmeBadgesCheck, From a4530b13becd8b0c6eec819649623fd024cf78e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 08:55:30 +0300 Subject: [PATCH 204/371] beman-tidy: more tweaks in docs --- tools/beman-tidy/docs/dev-guide.md | 40 ++++++++++-------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 434edbc4..8e8f40de 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -22,39 +22,25 @@ Limitations: ## Tree structure -```shell -$ ls -l -total 104 --rw-r--r-- 1 dariusn staff 4257 Jun 18 08:15 README.md -drwxr-xr-x 7 dariusn staff 224 Jun 18 08:29 beman_tidy -drwxr-xr-x 3 dariusn staff 96 Jun 18 08:25 docs --rw-r--r-- 1 dariusn staff 19490 Jun 18 08:15 pylock.toml --rw-r--r-- 1 dariusn staff 582 Jun 18 08:15 pyproject.toml -drwxr-xr-x 7 dariusn staff 224 Jun 18 08:29 tests --rw-r--r-- 1 dariusn staff 18975 Jun 18 08:15 uv.lock -``` - -* `beman-tidy`: All production code. -* `docs/`: The internal documentation for the `beman-tidy` tool. * `README.md`: The public documentation for the `beman-tidy` tool. -* `beman_tidy/`: The package for the `beman-tidy` tool. - * `beman_tidy/cli.py`: The CLI for the `beman-tidy` tool. - * `beman_tidy/lib/`: The library for the `beman-tidy` tool. - * `beman_tidy/lib/checks/`: The checks for the `beman-tidy` tool. - * `beman_tidy/lib/utils/`: The utility functions for the `beman-tidy` tool. - * `beman_tidy/lib/pipeline.py`: The pipeline for the `beman-tidy` tool. - * `beman_tidy/.beman-standard.yml`: Stable version of the standard; the tool does not fetch the latest unstable version of the standard. -* `tests/`: The tests for the `beman-tidy` tool. +* `docs/`: The internal documentation. +* `beman_tidy/`: The package/production code for the tool. + * `beman_tidy/cli.py`: The CLI / entry point for the tool. + * `beman_tidy/lib/`: The library for the tool. + * `beman_tidy/lib/checks/`: The checks for the tool. + * `beman_tidy/lib/pipeline.py`: The checks pipeline for the `beman-tidy` tool. + * `beman_tidy/.beman-standard.yml`: Stable (offline)version of the standard. +* `tests/`: Unit tests for the tool. * Structure is similar to the `beman_tidy/` directory. * `pytest` is used for testing. ## Adding a new check -* Add the check to the `beman_tidy/lib/checks/beman_standard/` directory. -* Add the check to the `beman_tidy/lib/pipeline.py` file. -* Add the check to the `tests/beman_standard/` directory. -* Add the check to the `docs/dev-guide.md` file. -* Add the check to the `README.md` file. +* Add the check to the `beman_tidy/lib/checks/beman_standard/` directory (e.g., `README.*` -> `beman_tidy/lib/checks/beman_standard/readme.py`). +* Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., `from .checks.beman_standard.readme import ReadmeTitleCheck`). +* Add tests for the check to the `tests/beman_standard/` directory (e.g., `README.*` -> `tests/lib/checks/beman_standard/readme/test_readme.py`). +* Updates docs if needed in `README.md` and `docs/dev-guide.md` files. +* Update the `beman_tidy/cli.py` file if the public API has changed. Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). From 819952f0a833d86e5056a156e615988ffbbd8981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 10:03:20 +0300 Subject: [PATCH 205/371] [beman-tidy] docs: add explicit wording --- tools/beman-tidy/docs/dev-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 8e8f40de..6db70a64 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -36,9 +36,9 @@ Limitations: ## Adding a new check -* Add the check to the `beman_tidy/lib/checks/beman_standard/` directory (e.g., `README.*` -> `beman_tidy/lib/checks/beman_standard/readme.py`). +* Add the check to the `beman_tidy/lib/checks/beman_standard/` directory (e.g., `README.*` checks will most likely go to a path similar to `beman_tidy/lib/checks/beman_standard/readme.py`). * Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., `from .checks.beman_standard.readme import ReadmeTitleCheck`). -* Add tests for the check to the `tests/beman_standard/` directory (e.g., `README.*` -> `tests/lib/checks/beman_standard/readme/test_readme.py`). +* Add tests for the check to the `tests/beman_standard/` directory (e.g., `README.*` checks tests will most likely go to a path similar to `tests/lib/checks/beman_standard/readme/test_readme.py`). * Updates docs if needed in `README.md` and `docs/dev-guide.md` files. * Update the `beman_tidy/cli.py` file if the public API has changed. From 133d10caffccae966c64cb4f6a92858f7420d657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 13:15:01 +0300 Subject: [PATCH 206/371] [beman-tody] Improve dev guide docs (#83) --- tools/beman-tidy/docs/dev-guide.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 6db70a64..58839503 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -36,11 +36,21 @@ Limitations: ## Adding a new check -* Add the check to the `beman_tidy/lib/checks/beman_standard/` directory (e.g., `README.*` checks will most likely go to a path similar to `beman_tidy/lib/checks/beman_standard/readme.py`). -* Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., `from .checks.beman_standard.readme import ReadmeTitleCheck`). -* Add tests for the check to the `tests/beman_standard/` directory (e.g., `README.*` checks tests will most likely go to a path similar to `tests/lib/checks/beman_standard/readme/test_readme.py`). -* Updates docs if needed in `README.md` and `docs/dev-guide.md` files. -* Update the `beman_tidy/cli.py` file if the public API has changed. +* `[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#L68) 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]` Use an appropiate 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") + class ReadmeTitleCheck(ReadmeBaseCheck): + ``` +* `[mandatory]` Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., `from .checks.beman_standard.readme import ReadmeTitleCheck`). +* `[mandatory]` Add tests for the check to the `tests/beman_standard/` directory. More in [Writing Tests](#writing-tests). +* `[optional]` Updates docs if needed in `README.md` and `docs/dev-guide.md` files. +* `[optional]` Update the `beman_tidy/cli.py` file if the public API has changed. Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). @@ -80,14 +90,14 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI ### Writing Tests -* `tests/beman_standard//test_.py`: The test file for the `` check. - * e.g., for `check_category = "readme"` the test file is `tests/beman_standard/readme/test_readme.py`. +* `tests/lib/checks/beman_standard//test_.py`: The test file for the `` 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()`. * `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/beman_standard/readme/data/valid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in `tests/beman_standard/readme/data/invalid/`. + * e.g., for `check_category = "readme"` and `test_case_name = "valid"` the data is in `tests/lib/checks/beman_standard/readme/data/valid/`. + * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in `tests/lib/checks/beman_standard/readme/data/invalid/`. * e.g., for `check_category = "readme"` and `test_case_name = "fix_invalid"` the data may use both `valid` and `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` (which are not tracked by git). * Default setup / mocks: * `repo_info`: The repository information (e.g., path, name, etc.). Mocked with hardcoded values of `beman.exemplar`. From c7122bb1ba96ce1c324d2fb0bfcf9644f8c1f18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:04:17 +0300 Subject: [PATCH 207/371] beman-tidy: README.BADGES is actually a requirement --- tools/beman-tidy/beman_tidy/.beman-standard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index d7d34c4d..ad395893 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -56,7 +56,7 @@ TOPLEVEL.README: README.TITLE: - type: RECOMMENDATION README.BADGES: - - type: RECOMMENDATION + - type: REQUIREMENT - values: [ "![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)", From e881c815dc49dc7e84a4d52c41dc86748babab6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:10:04 +0300 Subject: [PATCH 208/371] beman-tidy: cleanup in README related tests --- .../checks/beman_standard/readme/conftest.py | 19 ------------------- .../beman_standard/readme/test_readme.py | 6 +++--- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py index e3acbb06..a341a25c 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py @@ -6,25 +6,6 @@ from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 - -@pytest.fixture -def test_data_dir(): - """Return the path to the test data directory""" - return Path(__file__).parent / "data" - - -@pytest.fixture -def valid_readme_path(test_data_dir): - """Return the path to a valid README.md file""" - return test_data_dir / "valid" / "README.md" - - -@pytest.fixture -def invalid_readme_path(test_data_dir): - """Return the path to an invalid README.md file""" - return test_data_dir / "invalid" / "README.md" - - @pytest.fixture(autouse=True) def repo_info(mock_repo_info): # noqa: F811 return mock_repo_info diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index cdf841b3..a4361fb4 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -56,7 +56,7 @@ def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config) -def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_readme_path): +def test__README_BADGES__valid(repo_info, beman_standard_check_config): """Test that a valid README.md badges passes the check""" valid_readme_paths = [ Path(f"{valid_prefix}/README-v1.md"), @@ -69,7 +69,7 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_rea repo_info, beman_standard_check_config) -def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid_readme_path): +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"), @@ -83,6 +83,6 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid @pytest.mark.skip(reason="NOT implemented") -def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): +def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config): """Test that the fix method corrects an invalid README.md badges""" pass From b204596caa82e1c2086dd0bc19b926d586e0fe22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:10:52 +0300 Subject: [PATCH 209/371] beman-tidy: automatically import registered check classes into the pipeline --- tools/beman-tidy/beman_tidy/lib/pipeline.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index fc51c859..5f286e52 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -6,16 +6,16 @@ from .checks.system.registry import get_registered_beman_standard_checks from .checks.system.git import DisallowFixInplaceAndUnstagedChangesCheck -# Import all the implemented checks. -# from .checks.beman_standard.cmake import -# from .checks.beman_standard.cpp import -# from .checks.beman_standard.directory import -# from .checks.beman_standard.file import -# from .checks.beman_standard.general import -# from .checks.beman_standard.license import -from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck # noqa: F401 -# from .checks.beman_standard.release import -# from .checks.beman_standard.toplevel import +# import all the implemented checks. +from .checks.beman_standard.cmake import * # noqa: F401 +from .checks.beman_standard.cpp import * # noqa: F401 +from .checks.beman_standard.directory import * # noqa: F401 +from .checks.beman_standard.file import * # noqa: F401 +from .checks.beman_standard.general import * # noqa: F401 +from .checks.beman_standard.license import * # noqa: F401 +from .checks.beman_standard.readme import * # noqa: F401 +from .checks.beman_standard.release import * # noqa: F401 +from .checks.beman_standard.toplevel import * # noqa: F401 red_color = "\033[91m" green_color = "\033[92m" From a65867a1baf56d0785ba344f3f188cdfae750490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:13:57 +0300 Subject: [PATCH 210/371] beman-tidy: add directory APIs in the framework --- .../lib/checks/base/directory_base_check.py | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py index 37f1023f..0c1e5c60 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py @@ -21,12 +21,24 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): def pre_check(self): """ Override. + Pre-checks if the directory exists and is not empty. """ if not super().pre_check(): return False - # TODO: Implement the default check. - pass + if self.path is None: + self.log("The path is not set.") + return False + + if not os.path.exists(self.path): + self.log(f"The directory '{self.path}' does not exist.") + return False + + if self.is_empty(): + self.log(f"The directory '{self.path}' is empty.") + return False + + return True @abstractmethod def check(self): @@ -42,4 +54,17 @@ def fix(self): """ pass - # TODO: add methods to read the directory content + def read(self): + """ + Read the directory content. + """ + try: + return os.listdir(self.path) + except Exception: + return [] + + def is_empty(self): + """ + Check if the directory is empty. + """ + return len(self.read()) == 0 From 8529f374e106ebf6c8bb2589a8619fa994fc4147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:15:29 +0300 Subject: [PATCH 211/371] beman-tidy: implement DIRECTORY.SOURCES --- .../lib/checks/beman_standard/directory.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index f7d0d474..a5f6c926 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,7 +1,17 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from ..base.directory_base_check import DirectoryBaseCheck +from ..system.registry import register_beman_standard_check + # [DIRECTORY.*] checks category. +class BemanTreeDirectoryCheck(DirectoryBaseCheck): + """ + Check if the directory tree is a Beman tree. + """ + + def __init__(self, repo_info, beman_standard_check_config, prefix_path): + super().__init__(repo_info, beman_standard_check_config, f"{prefix_path}/beman/{repo_info['name']}") # TODO DIRECTORY.INTERFACE_HEADERS @@ -11,6 +21,22 @@ # TODO DIRECTORY.SOURCES +@register_beman_standard_check("DIRECTORY.SOURCES") +class DirectorySourcesCheck(BemanTreeDirectoryCheck): + """ + Check if the sources directory is src/beman/. + """ + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "src") + + def check(self): + return self.pre_check() + + def fix(self): + """ + TODO: Implement the fix. + """ + pass # TODO DIRECTORY.TESTS From 5b8dc589d8aff45f368601811f645901b4a668f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:45:27 +0300 Subject: [PATCH 212/371] beman-tidy: add require-all CLI argument --- tools/beman-tidy/beman_tidy/cli.py | 6 ++ tools/beman-tidy/beman_tidy/lib/pipeline.py | 69 ++++++++++++++++----- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/cli.py b/tools/beman-tidy/beman_tidy/cli.py index 9c25c59e..94cc879f 100755 --- a/tools/beman-tidy/beman_tidy/cli.py +++ b/tools/beman-tidy/beman_tidy/cli.py @@ -27,6 +27,12 @@ def parse_args(): action=argparse.BooleanOptionalAction, default=False, ) + parser.add_argument( + "--require-all", + help="all checks are required regardless of the check type (e.g., RECOMMENDATION becomes REQUIREMENT)", + action=argparse.BooleanOptionalAction, + default=False, + ) parser.add_argument( "--checks", help="array of checks to run", type=str, default=None ) diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index 5f286e52..eb7eb1cf 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -50,16 +50,17 @@ def run_check(check_class, log_enabled=args.verbose): 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}] ... ") 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") - return True + return check_type, True else: log(f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}FAILED{no_color}\n") - return False + return check_type, False """ Main pipeline. @@ -71,19 +72,46 @@ def run_pipeline_helper(): log_enabled=False) implemented_checks = get_registered_beman_standard_checks() - cnt_all_beman_standard_checks = len(beman_standard_check_config) - cnt_implemented_checks = len(implemented_checks) - cnt_passed = 0 - cnt_failed = 0 - cnt_skipped = cnt_all_beman_standard_checks - cnt_implemented_checks + all_checks = beman_standard_check_config + + cnt_passed = { + "REQUIREMENT": 0, + "RECOMMENDATION": 0, + } + cnt_failed = { + "REQUIREMENT": 0, + "RECOMMENDATION": 0, + } for check_name in checks_to_run: if check_name not in implemented_checks: continue - if run_check(implemented_checks[check_name]): - cnt_passed += 1 + check_type, passed = run_check(implemented_checks[check_name]) + if passed: + cnt_passed[check_type] += 1 else: - cnt_failed += 1 + cnt_failed[check_type] += 1 + + cnt_skipped = { + "REQUIREMENT": 0, + "RECOMMENDATION": 0, + } + cnt_all_beman_standard_checks = { + "REQUIREMENT": 0, + "RECOMMENDATION": 0, + } + cnt_implemented_checks = { + "REQUIREMENT": 0, + "RECOMMENDATION": 0, + } + for check_name in all_checks: + check_type = all_checks[check_name]["type"] + cnt_all_beman_standard_checks[check_type] += 1 + + if check_name not in implemented_checks: + cnt_skipped[check_type] += 1 + else: + cnt_implemented_checks[check_type] += 1 return cnt_passed, cnt_failed, cnt_skipped, cnt_implemented_checks, cnt_all_beman_standard_checks @@ -92,13 +120,24 @@ def run_pipeline_helper(): log("\nbeman-tidy pipeline finished.\n") # Always print the summary. - print(f"Summary: {green_color} {cnt_passed} checks PASSED{no_color}, {red_color}{cnt_failed} checks FAILED{no_color}, {gray_color}{cnt_skipped} skipped (NOT implemented).{no_color}") + 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}") + 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}") # Always print the coverage. - coverage = round(cnt_passed / cnt_implemented_checks * 100, 2) + coverage_requirement = round(cnt_passed['REQUIREMENT'] / cnt_implemented_checks['REQUIREMENT'] * 100, 2) + coverage_recommendation = round(cnt_passed['RECOMMENDATION'] / cnt_implemented_checks['RECOMMENDATION'] * 100, 2) + total_coverage = round((cnt_passed['REQUIREMENT'] + cnt_passed['RECOMMENDATION']) / (cnt_implemented_checks['REQUIREMENT'] + cnt_implemented_checks['RECOMMENDATION']) * 100, 2) print( - f"\n{yellow_color}Coverage: {coverage}% ({cnt_passed}/{cnt_implemented_checks} checks passed).{no_color}") + f"\n{green_color if coverage_requirement == 100 else red_color}Coverage REQUIREMENT: {coverage_requirement}% ({cnt_passed['REQUIREMENT']}/{cnt_implemented_checks['REQUIREMENT']} checks passed).{no_color}") + if args.require-all: + print( + f"{green_color if coverage_recommendation == 100 else red_color}Coverage RECOMMENDATION: {coverage_recommendation}% ({cnt_passed['RECOMMENDATION']}/{cnt_implemented_checks['RECOMMENDATION']} checks passed).{no_color}") + else: + print(f"Note: RECOMMENDATION coverage is not printed because --enforce-all is not set.") - sys.stdout.flush() + total_cnt_failed = cnt_failed['REQUIREMENT'] + (cnt_failed['RECOMMENDATION'] if args.require-all else 0) + if total_cnt_failed > 0: + print(f"{red_color}Total failed checks: {total_cnt_failed}.{no_color}") - return cnt_failed + sys.stdout.flush() + return total_cnt_failed From 28aa44a4131de8b801391557cabf1e9aecaef8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 14:48:26 +0300 Subject: [PATCH 213/371] [beman-tidy] extend framework to process directories (#84) --- .../beman-tidy/beman_tidy/.beman-standard.yml | 2 +- .../lib/checks/base/directory_base_check.py | 31 +++++++++++++++++-- .../lib/checks/beman_standard/directory.py | 26 ++++++++++++++++ tools/beman-tidy/beman_tidy/lib/pipeline.py | 20 ++++++------ .../checks/beman_standard/readme/conftest.py | 20 ------------ .../beman_standard/readme/test_readme.py | 6 ++-- 6 files changed, 68 insertions(+), 37 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index d7d34c4d..ad395893 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -56,7 +56,7 @@ TOPLEVEL.README: README.TITLE: - type: RECOMMENDATION README.BADGES: - - type: RECOMMENDATION + - type: REQUIREMENT - values: [ "![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)", diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py index 37f1023f..0c1e5c60 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py @@ -21,12 +21,24 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): def pre_check(self): """ Override. + Pre-checks if the directory exists and is not empty. """ if not super().pre_check(): return False - # TODO: Implement the default check. - pass + if self.path is None: + self.log("The path is not set.") + return False + + if not os.path.exists(self.path): + self.log(f"The directory '{self.path}' does not exist.") + return False + + if self.is_empty(): + self.log(f"The directory '{self.path}' is empty.") + return False + + return True @abstractmethod def check(self): @@ -42,4 +54,17 @@ def fix(self): """ pass - # TODO: add methods to read the directory content + def read(self): + """ + Read the directory content. + """ + try: + return os.listdir(self.path) + except Exception: + return [] + + def is_empty(self): + """ + Check if the directory is empty. + """ + return len(self.read()) == 0 diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index f7d0d474..a5f6c926 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,7 +1,17 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from ..base.directory_base_check import DirectoryBaseCheck +from ..system.registry import register_beman_standard_check + # [DIRECTORY.*] checks category. +class BemanTreeDirectoryCheck(DirectoryBaseCheck): + """ + Check if the directory tree is a Beman tree. + """ + + def __init__(self, repo_info, beman_standard_check_config, prefix_path): + super().__init__(repo_info, beman_standard_check_config, f"{prefix_path}/beman/{repo_info['name']}") # TODO DIRECTORY.INTERFACE_HEADERS @@ -11,6 +21,22 @@ # TODO DIRECTORY.SOURCES +@register_beman_standard_check("DIRECTORY.SOURCES") +class DirectorySourcesCheck(BemanTreeDirectoryCheck): + """ + Check if the sources directory is src/beman/. + """ + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, "src") + + def check(self): + return self.pre_check() + + def fix(self): + """ + TODO: Implement the fix. + """ + pass # TODO DIRECTORY.TESTS diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index fc51c859..5f286e52 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -6,16 +6,16 @@ from .checks.system.registry import get_registered_beman_standard_checks from .checks.system.git import DisallowFixInplaceAndUnstagedChangesCheck -# Import all the implemented checks. -# from .checks.beman_standard.cmake import -# from .checks.beman_standard.cpp import -# from .checks.beman_standard.directory import -# from .checks.beman_standard.file import -# from .checks.beman_standard.general import -# from .checks.beman_standard.license import -from .checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck # noqa: F401 -# from .checks.beman_standard.release import -# from .checks.beman_standard.toplevel import +# import all the implemented checks. +from .checks.beman_standard.cmake import * # noqa: F401 +from .checks.beman_standard.cpp import * # noqa: F401 +from .checks.beman_standard.directory import * # noqa: F401 +from .checks.beman_standard.file import * # noqa: F401 +from .checks.beman_standard.general import * # noqa: F401 +from .checks.beman_standard.license import * # noqa: F401 +from .checks.beman_standard.readme import * # noqa: F401 +from .checks.beman_standard.release import * # noqa: F401 +from .checks.beman_standard.toplevel import * # noqa: F401 red_color = "\033[91m" green_color = "\033[92m" diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py index e3acbb06..8aca7010 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py @@ -2,29 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import pytest -from pathlib import Path from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 - -@pytest.fixture -def test_data_dir(): - """Return the path to the test data directory""" - return Path(__file__).parent / "data" - - -@pytest.fixture -def valid_readme_path(test_data_dir): - """Return the path to a valid README.md file""" - return test_data_dir / "valid" / "README.md" - - -@pytest.fixture -def invalid_readme_path(test_data_dir): - """Return the path to an invalid README.md file""" - return test_data_dir / "invalid" / "README.md" - - @pytest.fixture(autouse=True) def repo_info(mock_repo_info): # noqa: F811 return mock_repo_info diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index cdf841b3..a4361fb4 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -56,7 +56,7 @@ def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config) -def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_readme_path): +def test__README_BADGES__valid(repo_info, beman_standard_check_config): """Test that a valid README.md badges passes the check""" valid_readme_paths = [ Path(f"{valid_prefix}/README-v1.md"), @@ -69,7 +69,7 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config, valid_rea repo_info, beman_standard_check_config) -def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid_readme_path): +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"), @@ -83,6 +83,6 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config, invalid @pytest.mark.skip(reason="NOT implemented") -def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config, invalid_readme_path, valid_readme_path): +def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config): """Test that the fix method corrects an invalid README.md badges""" pass From fcfb649fd954a6cca30188a076e1ebf8ee033eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 15:02:43 +0300 Subject: [PATCH 214/371] beman-tidy: add require-all docs --- tools/beman-tidy/README.md | 85 +++++++++++++-------- tools/beman-tidy/beman_tidy/cli.py | 2 +- tools/beman-tidy/beman_tidy/lib/pipeline.py | 8 +- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 2e4e6815..19fae9f5 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -53,72 +53,97 @@ usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verb ```shell $ uv run beman-tidy --help -usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path +usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--require-all | --no-require-all] [--checks CHECKS] repo_path positional arguments: repo_path path to the repository to check -optional arguments: +options: -h, --help show this help message and exit --fix-inplace, --no-fix-inplace - Try to automatically fix found issues (default: False) + Try to automatically fix found issues --verbose, --no-verbose - print verbose output for each check (default: False) + 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) --checks CHECKS array of checks to run ``` * Run beman-tidy on the exemplar repository **(default: dry-run mode)** + ```shell -$ uv run beman-tidy path/to/exemplar -# non-verbose mode -Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). +# 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). + +Coverage REQUIREMENT: 100.0% (1/1 checks passed). +Coverage RECOMMENDATION: 66.67% (2/3 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: 66.67% (2/3 checks passed). +Coverage REQUIREMENT: 100.0% (1/1 checks passed). +Note: RECOMMENDATIONs are not included (--require-all NOT set). -# verbose mode - no errors -$ uv run beman-tidy /path/to/exemplar --verbose +``` + +or verbose mode: +```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] ... - [WARNING ][README.TITLE ]: The first line of the file '/Users/dariusn/dev/dn/git/Beman/exemplar/README.md' is invalid. It should start with '# beman.exemplar: '. - check [RECOMMENDATION][README.TITLE] ... FAILED +Running check [RECOMMENDATION][README.TITLE] ... + check [RECOMMENDATION][README.TITLE] ... PASSED - Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED +Running check [REQUIREMENT][README.BADGES] ... + check [REQUIREMENT][README.BADGES] ... PASSED - Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED +Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... + check [RECOMMENDATION][README.LIBRARY_STATUS] ... 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 - beman-tidy pipeline finished. - Summary: 2 checks PASSED, 1 checks FAILED, 40 skipped (NOT implemented). +beman-tidy pipeline finished. -Coverage: 66.67% (2/3 checks passed). -``` +Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). +Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). -- Run beman-tidy in verbose mode +Coverage REQUIREMENT: 100.0% (1/1 checks passed). +Coverage RECOMMENDATION: 66.67% (2/3 checks passed). +``` -```shell -$ uv run /path/to/exemplar --verbose +# 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 + check [RECOMMENDATION][README.TITLE] ... PASSED -Running check [RECOMMENDATION][README.BADGES] ... - check [RECOMMENDATION][README.BADGES] ... PASSED +Running check [REQUIREMENT][README.BADGES] ... + check [REQUIREMENT][README.BADGES] ... PASSED Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + +Running check [RECOMMENDATION][DIRECTORY.SOURCES] ... + check [RECOMMENDATION][DIRECTORY.SOURCES] ... PASSED beman-tidy pipeline finished. -Summary: 3 checks PASSED, 0 checks FAILED, 40 skipped (NOT implemented). +Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). +Summary RECOMMENDATION: 3 checks PASSED, 0 checks FAILED, 35 skipped (NOT implemented). -Coverage: 100.0% (3/3 checks passed). +Coverage REQUIREMENT: 100.0% (1/1 checks passed). +Coverage RECOMMENDATION: 100.0% (3/3 checks passed). ``` * Run beman-tidy on the exemplar repository (fix issues in-place): diff --git a/tools/beman-tidy/beman_tidy/cli.py b/tools/beman-tidy/beman_tidy/cli.py index 94cc879f..7ae1c4d2 100755 --- a/tools/beman-tidy/beman_tidy/cli.py +++ b/tools/beman-tidy/beman_tidy/cli.py @@ -29,7 +29,7 @@ def parse_args(): ) parser.add_argument( "--require-all", - help="all checks are required regardless of the check type (e.g., RECOMMENDATION becomes REQUIREMENT)", + help="all checks are required regardless of their type (e.g., all RECOMMENDATIONs become REQUIREMENTs)", action=argparse.BooleanOptionalAction, default=False, ) diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index eb7eb1cf..7d661b79 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -129,15 +129,13 @@ def run_pipeline_helper(): total_coverage = round((cnt_passed['REQUIREMENT'] + cnt_passed['RECOMMENDATION']) / (cnt_implemented_checks['REQUIREMENT'] + cnt_implemented_checks['RECOMMENDATION']) * 100, 2) print( f"\n{green_color if coverage_requirement == 100 else red_color}Coverage REQUIREMENT: {coverage_requirement}% ({cnt_passed['REQUIREMENT']}/{cnt_implemented_checks['REQUIREMENT']} checks passed).{no_color}") - if args.require-all: + if args.require_all: print( f"{green_color if coverage_recommendation == 100 else red_color}Coverage RECOMMENDATION: {coverage_recommendation}% ({cnt_passed['RECOMMENDATION']}/{cnt_implemented_checks['RECOMMENDATION']} checks passed).{no_color}") else: - print(f"Note: RECOMMENDATION coverage is not printed because --enforce-all is not set.") + 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) - total_cnt_failed = cnt_failed['REQUIREMENT'] + (cnt_failed['RECOMMENDATION'] if args.require-all else 0) - if total_cnt_failed > 0: - print(f"{red_color}Total failed checks: {total_cnt_failed}.{no_color}") sys.stdout.flush() return total_cnt_failed From f47347df5179b3044a584a60053cefd56a4714eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 18 Jun 2025 15:13:28 +0300 Subject: [PATCH 215/371] beman-tidy: sync .beman-standard.yml --- .../beman-tidy/beman_tidy/.beman-standard.yml | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index ad395893..78551b4b 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -29,7 +29,7 @@ REPOSITORY.NAME: - type: RECOMMENDATION - regex: REPOSITORY.CODEOWNERS: - - type: RECOMMENDATION + - type: REQUIREMENT - default_group: "@bemanproject/core-reviewers" REPOSITORY.DISALLOW_GIT_SUBMODULES: - type: RECOMMENDATION @@ -43,13 +43,13 @@ RELEASE.GODBOLT_TRUNK_VERSION: - type: RECOMMENDATION # TOP LEVEL TOPLEVEL.CMAKE: - - type: RECOMMENDATION + - type: REQUIREMENT - file_name: CMakeLists.txt TOPLEVEL.LICENSE: - - type: RECOMMENDATION + - type: REQUIREMENT - file_name: LICENSE TOPLEVEL.README: - - type: RECOMMENDATION + - type: REQUIREMENT - file_name: README.md # README @@ -68,7 +68,7 @@ README.PURPOSE: README.IMPLEMENTS: - type: RECOMMENDATION README.LIBRARY_STATUS: - - type: RECOMMENDATION + - 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)", @@ -89,14 +89,16 @@ CMAKE.LIBRARY_NAME: - type: RECOMMENDATION - regex: CMAKE.LIBRARY_ALIAS: - - type: RECOMMENDATION + - type: REQUIREMENT - regex: CMAKE.TARGET_NAMES: - type: RECOMMENDATION - regex: CMAKE.PASSIVE_TARGETS: - - type: RECOMMENDATION + - type: REQUIREMENT - regex: +CMAKE.CONFIG: + - type: REQUIREMENT CMAKE.SKIP_TESTS: - type: RECOMMENDATION - regex: @@ -108,30 +110,30 @@ CMAKE.AVOID_PASSTHROUGHS: # DIRECTORY DIRECTORY.INTERFACE_HEADERS: - - type: RECOMMENDATION + - type: REQUIREMENT - directory_name: include - regex: DIRECTORY.IMPLEMENTATION_HEADERS: - - type: RECOMMENDATION + - type: REQUIREMENT - regex: DIRECTORY.SOURCES: - - type: RECOMMENDATION + - type: REQUIREMENT - directory_name: src - regex: DIRECTORY.TESTS: - - type: RECOMMENDATION + - type: REQUIREMENT - directory_name: tests - regex: DIRECTORY.EXAMPLES: - - type: RECOMMENDATION + - type: REQUIREMENT - directory_name: examples - regex: DIRECTORY.DOCS: - - type: RECOMMENDATION + - type: REQUIREMENT - directory_name: docs - regex: DIRECTORY.PAPERS: - - type: RECOMMENDATION + - type: REQUIREMENT - directory_name: papers # FILE @@ -139,10 +141,10 @@ FILE.CPP_NAMES: - type: RECOMMENDATION - regex: FILE.TEST_NAMES: - - type: RECOMMENDATION + - type: REQUIREMENT - regex: FILE.LICENSE_ID: - - type: RECOMMENDATION + - type: REQUIREMENT - regex: [ "// SPDX-License-Identifier: ", "# SPDX-License-Identifier: ", From 5421759ada475b5a3f7bc9da14ba42b89e0e6824 Mon Sep 17 00:00:00 2001 From: Tsche Date: Thu, 19 Jun 2025 08:11:07 +0200 Subject: [PATCH 216/371] [beman-tidy] consistently use pathlib.Path rather than os.path --- tools/beman-submodule/beman-submodule | 64 ++++++++------ .../test/test_beman_submodule.py | 88 ++++++++++--------- .../beman_tidy/lib/checks/base/base_check.py | 6 +- .../lib/checks/base/directory_base_check.py | 11 +-- .../lib/checks/base/file_base_check.py | 5 +- tools/beman-tidy/beman_tidy/lib/utils/git.py | 14 +-- .../tests/utils/file_testcase_runners.py | 6 +- 7 files changed, 107 insertions(+), 87 deletions(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 2007fc49..9fe09aad 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -6,26 +6,29 @@ import argparse import configparser import filecmp import os -import pathlib import shutil import subprocess import sys import tempfile +from pathlib import Path + + +def directory_compare(dir1: str | Path, dir2: str | Path, ignore): + dir1, dir2 = Path(dir1), Path(dir2) -def directory_compare(dir1, dir2, ignore): compared = filecmp.dircmp(dir1, dir2, ignore=ignore) if compared.left_only or compared.right_only or compared.diff_files: return False for common_dir in compared.common_dirs: - path1 = os.path.join(dir1, common_dir) - path2 = os.path.join(dir2, common_dir) + path1 = dir1 / common_dir + path2 = dir2 / common_dir if not directory_compare(path1, path2, ignore): return False return True class BemanSubmodule: - def __init__(self, dirpath, remote, commit_hash): - self.dirpath = dirpath + def __init__(self, dirpath: str | Path, remote: str, commit_hash: str): + self.dirpath = Path(dirpath) self.remote = remote self.commit_hash = commit_hash @@ -43,22 +46,26 @@ def parse_beman_submodule_file(path): if not 'commit_hash' in config['beman_submodule']: fail() return BemanSubmodule( - str(pathlib.Path(path).resolve().parent), - config['beman_submodule']['remote'], config['beman_submodule']['commit_hash']) + Path(path).resolve().parent, + config['beman_submodule']['remote'], + config['beman_submodule']['commit_hash']) -def get_beman_submodule(dir): - beman_submodule_filepath = os.path.join(dir, '.beman_submodule') - if os.path.isfile(beman_submodule_filepath): +def get_beman_submodule(path: str | Path): + beman_submodule_filepath = Path(path) / '.beman_submodule' + + if beman_submodule_filepath.is_file(): return parse_beman_submodule_file(beman_submodule_filepath) else: return None -def find_beman_submodules_in(dir): - assert os.path.isdir(dir) +def find_beman_submodules_in(path): + path = Path(path) + assert path.is_dir() + result = [] - for dirpath, _, filenames in os.walk(dir): + for dirpath, _, filenames in path.walk(): if '.beman_submodule' in filenames: - result.append(parse_beman_submodule_file(os.path.join(dirpath, '.beman_submodule'))) + result.append(parse_beman_submodule_file(dirpath / '.beman_submodule')) return sorted(result, key=lambda module: module.dirpath) def cwd_git_repository_path(): @@ -92,19 +99,22 @@ def beman_submodule_status(beman_submodule): parent_repo_path = cwd_git_repository_path() if not parent_repo_path: raise Exception('this is not a git repository') - relpath = pathlib.Path( - beman_submodule.dirpath).relative_to(pathlib.Path(parent_repo_path)) + relpath = Path(beman_submodule.dirpath).relative_to(Path(parent_repo_path)) return status_character + ' ' + beman_submodule.commit_hash + ' ' + str(relpath) def beman_submodule_update(beman_submodule, remote): tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, remote) + tmp_path = Path(tmpdir.name) + shutil.rmtree(beman_submodule.dirpath) - with open(os.path.join(tmpdir.name, '.beman_submodule'), 'w') as f: + + submodule_path = tmp_path / '.beman_submodule' + with open(submodule_path, 'w') as f: f.write('[beman_submodule]\n') f.write(f'remote={beman_submodule.remote}\n') f.write(f'commit_hash={beman_submodule.commit_hash}\n') - shutil.rmtree(os.path.join(tmpdir.name, '.git')) - shutil.copytree(tmpdir.name, beman_submodule.dirpath) + shutil.rmtree(tmp_path / '.git') + shutil.copytree(tmp_path, beman_submodule.dirpath) def update_command(remote, path): if not path: @@ -126,19 +136,21 @@ def add_command(repository, path): ['git', 'clone', repository], capture_output=True, check=True, cwd=tmpdir.name) repository_name = os.listdir(tmpdir.name)[0] if not path: - path = repository_name - if os.path.exists(path): + path = Path(repository_name) + else: + path = Path(path) + if path.exists(): raise Exception(f'{path} exists') - os.makedirs(path) - tmpdir_repo = os.path.join(tmpdir.name, repository_name) + path.mkdir() + tmpdir_repo = Path(tmpdir.name) / repository_name sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir_repo) - with open(os.path.join(tmpdir_repo, '.beman_submodule'), 'w') as f: + with open(tmpdir_repo / '.beman_submodule', 'w') as f: f.write('[beman_submodule]\n') f.write(f'remote={repository}\n') f.write(f'commit_hash={sha_process.stdout.strip()}\n') - shutil.rmtree(os.path.join(tmpdir_repo, '.git')) + shutil.rmtree(tmpdir_repo /'.git') shutil.copytree(tmpdir_repo, path, dirs_exist_ok=True) def status_command(paths): diff --git a/tools/beman-submodule/test/test_beman_submodule.py b/tools/beman-submodule/test/test_beman_submodule.py index 47e2303c..5010b8a7 100644 --- a/tools/beman-submodule/test/test_beman_submodule.py +++ b/tools/beman-submodule/test/test_beman_submodule.py @@ -1,27 +1,29 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import os -import pathlib import pytest import shutil import stat import subprocess import tempfile +from pathlib import Path # https://stackoverflow.com/a/19011259 import types import importlib.machinery loader = importlib.machinery.SourceFileLoader( 'beman_submodule', - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../beman-submodule')) + str(Path(__file__).parent.resolve().parent / 'beman-submodule')) beman_submodule = types.ModuleType(loader.name) loader.exec_module(beman_submodule) def create_test_git_repository(): tmpdir = tempfile.TemporaryDirectory() + tmp_path = Path(tmpdir.name) + subprocess.run(['git', 'init'], check=True, cwd=tmpdir.name, capture_output=True) def make_commit(a_txt_contents): - with open(os.path.join(tmpdir.name, 'a.txt'), 'w') as f: + with open(tmp_path / 'a.txt', 'w') as f: f.write(a_txt_contents) subprocess.run( ['git', 'add', 'a.txt'], check=True, cwd=tmpdir.name, capture_output=True) @@ -34,28 +36,30 @@ def make_commit(a_txt_contents): return tmpdir def test_directory_compare(): - def create_dir_structure(dir_path): - bar_path = os.path.join(dir_path, 'bar') + def create_dir_structure(dir_path: Path): + bar_path = dir_path / 'bar' os.makedirs(bar_path) - with open(os.path.join(dir_path, 'foo.txt'), 'w') as f: + with open(dir_path / 'foo.txt', 'w') as f: f.write('foo') - with open(os.path.join(bar_path, 'baz.txt'), 'w') as f: + with open(bar_path / 'baz.txt', 'w') as f: f.write('baz') with tempfile.TemporaryDirectory() as dir_a, \ tempfile.TemporaryDirectory() as dir_b: + path_a = Path(dir_a) + path_b = Path(dir_b) - create_dir_structure(dir_a) - create_dir_structure(dir_b) + create_dir_structure(path_a) + create_dir_structure(path_b) assert beman_submodule.directory_compare(dir_a, dir_b, []) - with open(os.path.join(os.path.join(dir_a, 'bar'), 'quux.txt'), 'w') as f: + with open(path_a / 'bar' / 'quux.txt', 'w') as f: f.write('quux') - assert not beman_submodule.directory_compare(dir_a, dir_b, []) - assert beman_submodule.directory_compare(dir_a, dir_b, ['quux.txt']) + assert not beman_submodule.directory_compare(path_a, path_b, []) + assert beman_submodule.directory_compare(path_a, path_b, ['quux.txt']) def test_parse_beman_submodule_file(): def valid_file(): @@ -67,7 +71,7 @@ def valid_file(): 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8')) tmpfile.flush() module = beman_submodule.parse_beman_submodule_file(tmpfile.name) - assert module.dirpath == str(pathlib.Path(tmpfile.name).resolve().parent) + assert module.dirpath == Path(tmpfile.name).resolve().parent assert module.remote == 'git@github.com:bemanproject/infra.git' assert module.commit_hash == '9b88395a86c4290794e503e94d8213b6c442ae77' valid_file() @@ -116,7 +120,7 @@ def invalid_file_wrong_section(): def test_get_beman_submodule(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') assert beman_submodule.get_beman_submodule('foo') @@ -127,7 +131,7 @@ def test_get_beman_submodule(): def test_find_beman_submodules_in(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') beman_submodule.add_command(tmpdir.name, 'bar') @@ -136,16 +140,16 @@ def test_find_beman_submodules_in(): ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) sha = sha_process.stdout.strip() - assert beman_submodules[0].dirpath == os.path.join(tmpdir2.name, 'bar') + assert beman_submodules[0].dirpath == Path(tmpdir2.name) / 'bar' assert beman_submodules[0].remote == tmpdir.name assert beman_submodules[0].commit_hash == sha - assert beman_submodules[1].dirpath == os.path.join(tmpdir2.name, 'foo') + assert beman_submodules[1].dirpath == Path(tmpdir2.name) / 'foo' assert beman_submodules[1].remote == tmpdir.name assert beman_submodules[1].commit_hash == sha os.chdir(original_cwd) def test_cwd_git_repository_path(): - original_cwd = os.getcwd() + original_cwd = Path.cwd() tmpdir = tempfile.TemporaryDirectory() os.chdir(tmpdir.name) assert not beman_submodule.cwd_git_repository_path() @@ -156,14 +160,14 @@ def test_cwd_git_repository_path(): def test_clone_beman_submodule_into_tmpdir(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, cwd=tmpdir.name) sha = sha_process.stdout.strip() beman_submodule.add_command(tmpdir.name, 'foo') - module = beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo')) + module = beman_submodule.get_beman_submodule(Path(tmpdir2.name) / 'foo') module.commit_hash = sha tmpdir3 = beman_submodule.clone_beman_submodule_into_tmpdir(module, False) assert not beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git']) @@ -178,7 +182,7 @@ def test_clone_beman_submodule_into_tmpdir(): def test_beman_submodule_status(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') sha_process = subprocess.run( @@ -186,17 +190,17 @@ def test_beman_submodule_status(): cwd=tmpdir.name) sha = sha_process.stdout.strip() assert ' ' + sha + ' foo' == beman_submodule.beman_submodule_status( - beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo'))) - with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), 'a.txt'), 'w') as f: + beman_submodule.get_beman_submodule(Path(tmpdir2.name) / 'foo')) + with open(Path(tmpdir2.name) / 'foo' / 'a.txt', 'w') as f: f.write('b') assert '+ ' + sha + ' foo' == beman_submodule.beman_submodule_status( - beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo'))) + beman_submodule.get_beman_submodule(Path(tmpdir2.name) / 'foo')) os.chdir(original_cwd) def test_update_command_no_paths(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') beman_submodule.add_command(tmpdir.name, 'bar') @@ -207,15 +211,15 @@ def test_update_command_no_paths(): subprocess.run( ['git', 'reset', '--hard', sha], capture_output=True, check=True, cwd=tmpdir.name) - with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'w') as f: + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'w') as f: f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') - with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), '.beman_submodule'), 'w') as f: + with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'w') as f: f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') beman_submodule.update_command(tmpdir.name, None) assert beman_submodule.directory_compare( - tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) assert beman_submodule.directory_compare( - tmpdir.name, os.path.join(tmpdir2.name, 'bar'), ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) os.chdir(original_cwd) def test_update_command_with_path(): @@ -223,7 +227,7 @@ def test_update_command_with_path(): tmpdir2 = create_test_git_repository() tmpdir_copy1 = tempfile.TemporaryDirectory() shutil.copytree(tmpdir.name, tmpdir_copy1.name, dirs_exist_ok=True) - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') beman_submodule.add_command(tmpdir.name, 'bar') @@ -234,21 +238,21 @@ def test_update_command_with_path(): subprocess.run( ['git', 'reset', '--hard', sha], capture_output=True, check=True, cwd=tmpdir.name) - with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'w') as f: + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'w') as f: f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') - with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), '.beman_submodule'), 'w') as f: + with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'w') as f: f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') beman_submodule.update_command(tmpdir.name, 'foo') assert beman_submodule.directory_compare( - tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) assert beman_submodule.directory_compare( - tmpdir_copy1.name, os.path.join(tmpdir2.name, 'bar'), ['.git', '.beman_submodule']) + tmpdir_copy1.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) os.chdir(original_cwd) def test_add_command(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') sha_process = subprocess.run( @@ -256,22 +260,22 @@ def test_add_command(): cwd=tmpdir.name) sha = sha_process.stdout.strip() assert beman_submodule.directory_compare( - tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule']) - with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'r') as f: + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'r') as f: assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n' os.chdir(original_cwd) def test_status_command_no_paths(capsys): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') beman_submodule.add_command(tmpdir.name, 'bar') sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) - with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), 'a.txt'), 'w') as f: + with open(Path(tmpdir2.name) / 'bar' / 'a.txt', 'w') as f: f.write('b') beman_submodule.status_command([]) sha = sha_process.stdout.strip() @@ -281,14 +285,14 @@ def test_status_command_no_paths(capsys): def test_status_command_with_path(capsys): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - original_cwd = os.getcwd() + original_cwd = Path.cwd() os.chdir(tmpdir2.name) beman_submodule.add_command(tmpdir.name, 'foo') beman_submodule.add_command(tmpdir.name, 'bar') sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) - with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), 'a.txt'), 'w') as f: + with open(Path(tmpdir2.name) / 'bar' / 'a.txt', 'w') as f: f.write('b') beman_submodule.status_command(['bar']) sha = sha_process.stdout.strip() @@ -298,7 +302,7 @@ def test_status_command_with_path(capsys): def test_check_for_git(): tmpdir = tempfile.TemporaryDirectory() assert not beman_submodule.check_for_git(tmpdir.name) - fake_git_path = os.path.join(tmpdir.name, 'git') + fake_git_path = Path(tmpdir.name) / 'git' with open(fake_git_path, 'w'): pass os.chmod(fake_git_path, stat.S_IRWXU) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py index 493da42b..1cb45b41 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from abc import ABC, abstractmethod +from pathlib import Path + from ..system.registry import get_beman_standard_check_name_by_class @@ -43,7 +45,7 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): assert "name" in repo_info self.repo_name = repo_info["name"] assert "top_level" in repo_info - self.repo_path = repo_info["top_level"] + self.repo_path = Path(repo_info["top_level"]) assert self.repo_path is not None self.library_name = f"beman.{self.repo_name}" assert self.library_name is not None @@ -69,7 +71,7 @@ def pre_check(self): self.log(f"The repo_name is not set for check = {self.name}.") return False - if self.repo_path is None: + if not self.repo_path: self.log(f"The repo_path is not set for check = {self.name}.") return False diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py index 0c1e5c60..12b0e163 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from abc import abstractmethod -import os +from pathlib import Path from .base_check import BaseCheck @@ -14,9 +14,10 @@ class DirectoryBaseCheck(BaseCheck): def __init__(self, repo_info, beman_standard_check_config, relative_path): super().__init__(repo_info, beman_standard_check_config) + print(repo_info) # set path - e.g. "src/beman/exemplar" - self.path = os.path.join(repo_info["top_level"], relative_path) + self.path = self.repo_path / relative_path def pre_check(self): """ @@ -30,7 +31,7 @@ def pre_check(self): self.log("The path is not set.") return False - if not os.path.exists(self.path): + if not self.path.exists(): self.log(f"The directory '{self.path}' does not exist.") return False @@ -54,12 +55,12 @@ def fix(self): """ pass - def read(self): + def read(self) -> list[Path]: """ Read the directory content. """ try: - return os.listdir(self.path) + return list(self.path.iterdir()) except Exception: return [] diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py index 07e9b83d..e816d91a 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from abc import abstractmethod -import os import re from .base_check import BaseCheck @@ -17,7 +16,7 @@ def __init__(self, repo_info, beman_standard_check_config, relative_path): super().__init__(repo_info, beman_standard_check_config) # set path - e.g. "README.md" - self.path = os.path.join(repo_info["top_level"], relative_path) + self.path = self.repo_path / relative_path def pre_check(self): """ @@ -31,7 +30,7 @@ def pre_check(self): self.log("The path is not set.") return False - if not os.path.exists(self.path): + if not self.path.exists(): self.log(f"The file '{self.path}' does not exist.") return False diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index 18b40434..6ef8786b 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -1,27 +1,29 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -import os import sys import yaml +from pathlib import Path + from git import Repo, InvalidGitRepositoryError -def get_repo_info(path): +def get_repo_info(path: str): """ Get information about the repository at the given path. Returns data as a dictionary. """ + path: Path = Path(path) try: # Initialize the repository object - repo = Repo(os.path.abspath(path), search_parent_directories=True) + repo = Repo(path.absolute(), search_parent_directories=True) # Get the top-level directory of the repository - top_level_dir = repo.git.rev_parse("--show-toplevel") + top_level_dir = Path(repo.git.rev_parse("--show-toplevel")) # Get the repository name (directory name of the top level) - repo_name = os.path.basename(top_level_dir) + repo_name = top_level_dir.name # Get the remote URL (assuming 'origin' is the remote name) remote_url = None @@ -62,7 +64,7 @@ def get_beman_standard_config_path(): """ Get the path to the Beman Standard YAML configuration file. """ - return os.path.join(os.path.dirname(__file__), "..", "..", ".beman-standard.yml") + return Path(__file__).parent.parent.parent / ".beman-standard.yml" def load_beman_standard_config(path=get_beman_standard_config_path()): diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index eaaf3475..b95839cc 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -2,11 +2,11 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import os - +from pathlib import Path def file_testcase_run(file_path, check_class, repo_info, beman_standard_check_config, expected_result): check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = file_path + check_instance.path = Path(file_path) check_instance.log_level = True assert check_instance.pre_check( @@ -27,7 +27,7 @@ def file_testcase_run_invalid(file_path, check_class, repo_info, beman_standard_ def file_testcase_run_fix_invalid(invalid_file_path, check_class, repo_info, beman_standard_check_config): check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = f"{invalid_file_path}.delete_me" + check_instance.path = Path(f"{invalid_file_path}.delete_me") check_instance.write(invalid_file_path.read_text()) assert check_instance.pre_check() is True From 630fab9dfe5b55caf2d38d45f184158bdb893d03 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Wed, 18 Jun 2025 13:54:19 -0500 Subject: [PATCH 217/371] beman-tidy: implement TOPLEVEL.CMAKE A simple check to verify the top-level CMake file exists and is not empty. --- .../beman-tidy/beman_tidy/.beman-standard.yml | 2 +- .../lib/checks/beman_standard/toplevel.py | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index 78551b4b..47519973 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -44,7 +44,7 @@ RELEASE.GODBOLT_TRUNK_VERSION: # TOP LEVEL TOPLEVEL.CMAKE: - type: REQUIREMENT - - file_name: CMakeLists.txt + - value: CMakeLists.txt TOPLEVEL.LICENSE: - type: REQUIREMENT - file_name: LICENSE diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 63f15ce4..cf83a0f6 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -1,10 +1,49 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from ..base.base_check import BaseCheck +from ..system.registry import register_beman_standard_check + # [TOPLEVEL.*] checks category. +# All checks in this file extend the ToplevelBaseCheck class. +# +# Note: ToplevelBaseCheck is not a registered check! + + +class ToplevelBaseCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + +@register_beman_standard_check("TOPLEVEL.CMAKE") +class ToplevelCmakeCheck(ToplevelBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + """ + self.config["value"] contains the CMake file name. + """ + self.path = self.repo_path / self.config["value"] + assert self.config["value"].endswith(".txt") + + if not self.path.exists(): + self.log("The top-level CMake file does not exist.") + return False + + try: + with open(self.path, 'r') as file: + if len(file.read()) == 0: + self.log("The top-level CMake file is empty.") + return False + except Exception: + self.log("Failed to read the top-level CMake file.") + return False -# TODO TOPLEVEL.CMAKE - use CMakeBaseCheck + return True + def fix(self): + # TODO: Implement the fix. + pass # TODO TOPLEVEL.LICENSE - use FileBaseCheck From 040a752c3e5fcbf7f9cd2a2257ef0d3629493364 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 23 Jun 2025 15:10:51 +0100 Subject: [PATCH 218/371] Remove Docker infrastructure files moved to bemanproject/containers The new repository, bemanproject/containers (https://github.com/bemanproject/containers), is the new home for the part of the infra repository that handles building the CI test and devcontainer Docker images used by Beman repositories. The git history of these files has been transferred over as well, using a git filter-repo command. --- .../docker_dev_container/devcontainer.json | 13 --- .github/workflows/build_devcontainer.yml | 97 ------------------- containers/Dockerfile | 37 ------- containers/README.md | 46 --------- containers/install_compiler.sh | 39 -------- containers/install_sys.sh | 10 -- 6 files changed, 242 deletions(-) delete mode 100644 .devcontainer/docker_dev_container/devcontainer.json delete mode 100644 .github/workflows/build_devcontainer.yml delete mode 100644 containers/Dockerfile delete mode 100644 containers/README.md delete mode 100644 containers/install_compiler.sh delete mode 100644 containers/install_sys.sh diff --git a/.devcontainer/docker_dev_container/devcontainer.json b/.devcontainer/docker_dev_container/devcontainer.json deleted file mode 100644 index 6707a25b..00000000 --- a/.devcontainer/docker_dev_container/devcontainer.json +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -{ - "name": "beman.infra Docker Devcontainer", - "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "features": { - "ghcr.io/devcontainers/features/docker-in-docker:2": { - "version": "latest", - "enableNonRootDocker": true, - "moby": false - }, - "ghcr.io/devcontainers-extra/features/pre-commit:2": {} - } -} diff --git a/.github/workflows/build_devcontainer.yml b/.github/workflows/build_devcontainer.yml deleted file mode 100644 index 1f26fc7f..00000000 --- a/.github/workflows/build_devcontainer.yml +++ /dev/null @@ -1,97 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -name: Publish Beman Containers - -on: - push: - paths: - - ".github/workflows/build_devcontainer.yml" - - "containers/**" - workflow_dispatch: - -env: - REGISTRY: ghcr.io - DEBUG_NAME: ${{ github.repository }} - DEPLOY_DEV_NAME_PREFIX: bemanproject/devcontainers - DEPLOY_TESTING_NAME_PREFIX: bemanproject/testingcontainers - BASE_IMAGE_DEV: mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 - BASE_IMAGE_TEST: ubuntu:24.04 - -permissions: - packages: write - -jobs: - containers: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - compilers: - - kind: gcc - version: 14 - - kind: gcc - version: 13 - - kind: gcc - version: 12 - - kind: gcc - version: 11 - - kind: clang - version: 21 - - kind: clang - version: 20 - - kind: clang - version: 19 - - kind: clang - version: 18 - - kind: clang - version: 17 - usage: [dev, test] - name: "${{ matrix.usage }}: ${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" - steps: - - name: Compute Image Name - id: image_name - run: | - if [ "${{ github.repository }}/${{ github.ref }}" != "bemanproject/infra/refs/heads/main" ]; then - image_name="${{ env.DEBUG_NAME }}" - tag="${{ matrix.usage }}-${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}" - else - if [ "${{ matrix.usage }}" = "dev" ]; then - image_name="${{ env.DEPLOY_DEV_NAME_PREFIX }}-${{ matrix.compilers.kind }}" - else - image_name="${{ env.DEPLOY_TESTING_NAME_PREFIX }}-${{ matrix.compilers.kind }}" - fi - tag="${{ matrix.compilers.version }}" - fi - - echo "Image Name: $image_name, Tag: $tag" - - echo "image_name=$image_name" >> "$GITHUB_OUTPUT" - echo "tag=$tag" >> "$GITHUB_OUTPUT" - - name: Compute Image base - id: image_base - run: | - if [ "${{ matrix.usage }}" == "dev" ]; then - echo "image=${{ env.BASE_IMAGE_DEV }}" >> "$GITHUB_OUTPUT" - else - echo "image=${{ env.BASE_IMAGE_TEST }}" >> "$GITHUB_OUTPUT" - fi - - name: Checkout repository - uses: actions/checkout@v4 - - name: Log in to the Container registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push Docker image - uses: docker/build-push-action@v6 - with: - context: containers - build-args: | - base_image=${{ steps.image_base.outputs.image }} - compiler_kind=${{ matrix.compilers.kind }} - compiler_version=${{ matrix.compilers.version }} - push: true - tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:${{ steps.image_name.outputs.tag }} - # https://github.com/docker/build-push-action/issues/894 - provenance: false diff --git a/containers/Dockerfile b/containers/Dockerfile deleted file mode 100644 index f5f5f9d0..00000000 --- a/containers/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -ARG base_image=mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04 -FROM ${base_image} - -# Create the vscode user -RUN bash </dev/null; then - apt-get update && apt-get install -y sudo adduser - useradd -ms /bin/bash -p "" vscode && usermod -aG sudo vscode - fi -EOF - -USER vscode -WORKDIR /tmp - -COPY install_sys.sh . -RUN bash install_sys.sh - -# Newer gcc/ clang is needed to avoid ASAN Stalling, which is turned on by default across beman projects. -# See: https://github.com/google/sanitizers/issues/1614 -# Minimal version: clang-18.1.3, gcc-13.2 -ARG compiler_kind=gcc -ARG compiler_version=14 - -COPY install_compiler.sh . -RUN bash install_compiler.sh ${compiler_kind} ${compiler_version} - -# Common dependency: google-test -RUN sudo apt-get install -y libgtest-dev - -# Pre-commit is beman library's standard linting tool -RUN sudo apt-get install -y pipx -RUN pipx install pre-commit -ENV PATH="/home/vscode/.local/bin:${PATH}" - -ENTRYPOINT ["/usr/bin/bash"] diff --git a/containers/README.md b/containers/README.md deleted file mode 100644 index 83b357df..00000000 --- a/containers/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Containers - - - -This folder contains the infrastructure for Beman project's -generic container images. You can checkout available images in beman's -[GitHub Packages page](https://github.com/orgs/bemanproject/packages). - -These images includes: - -- The latest CMake from kitware's apt repository -- Latest compiler based on build args (gcc or clang) installed from the universe repository -- [pre-commit](https://pre-commit.com/), the standard linter manager across Beman - -## Devcontainer - -The image is build on top of GitHub's -[C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp) -for Ubuntu 24.04. - -### Example devcontainer setup - -```json -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -{ - "name": "Beman Generic Devcontainer", - "image": "ghcr.io/bemanproject/devcontainers-gcc:14", - "postCreateCommand": "pre-commit", - "customizations": { - "vscode": { - "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cmake-tools" - ] - } - } -} -``` - -### Building your own image - -You can build your own Beman devcontainer image with: - -```bash -docker build devcontainer/ -``` diff --git a/containers/install_compiler.sh b/containers/install_compiler.sh deleted file mode 100644 index bef0e1c4..00000000 --- a/containers/install_compiler.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -set -e -set +x -TOOL=$1 -VERSION=$2 - -echo "Install ${TOOL} at: ${VERSION}" - -shopt -s nocasematch -if [ "$TOOL" = "gcc" ]; then - sudo apt-get remove -y gcc-"$VERSION" g++-"$VERSION" gcc g++ - sudo apt-get install -y gcc-"$VERSION" g++-"$VERSION" lcov - - sudo rm -f /usr/bin/gcc - sudo rm -f /usr/bin/g++ - sudo rm -f /usr/bin/gcov - - sudo ln -s "$(which gcc-"$VERSION")" /usr/bin/gcc - sudo ln -s "$(which g++-"$VERSION")" /usr/bin/g++ - sudo ln -s "$(which gcov-"$VERSION")" /usr/bin/gcov - - gcc --version -else - sudo apt-get install -y lsb-release wget software-properties-common gnupg - wget https://apt.llvm.org/llvm.sh - - sudo bash llvm.sh "${VERSION}" - sudo apt-get install -y libc++-"$VERSION"-dev clang-tools-"$VERSION" lcov - - sudo rm -f /usr/bin/clang - sudo rm -f /usr/bin/clang++ - - sudo ln -s "$(which clang-"$VERSION")" /usr/bin/clang - sudo ln -s "$(which clang++-"$VERSION")" /usr/bin/clang++ - - clang --version -fi diff --git a/containers/install_sys.sh b/containers/install_sys.sh deleted file mode 100644 index 0e31aca4..00000000 --- a/containers/install_sys.sh +++ /dev/null @@ -1,10 +0,0 @@ -# Install Basic utilities -sudo apt-get install -y ca-certificates gpg wget git curl - -# Install Latest CMake -wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null -echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null -sudo apt-get update && sudo apt-get install -y cmake - -# Install Ninja -sudo apt-get install -y ninja-build From ba2b6c45409cd03aeff78bb9106845c5590fc4e6 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Wed, 25 Jun 2025 10:45:28 +0100 Subject: [PATCH 219/371] markdownlint: Don't include code blocks in line length check Code blocks can include output from tools that should be displayed exactly as the tool produced it, and which also exceeds the configured line length that we want to use for prose. --- .markdownlint.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 81f5fcd7..21c28494 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -7,3 +7,4 @@ MD033: false # Update the comment in .clang-format if we no-longer tie these two column limits. MD013: line_length: 119 + code_blocks: false From 8757f128400a1696bbee4b7186f66250f71a9158 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Wed, 25 Jun 2025 10:35:32 +0100 Subject: [PATCH 220/371] pre-commit: Add exemplar's checks, make them pass, add them to CI Previously, although infra provided beman-tidy as a pre-commit hook to consumers of the repository, it did not use pre-commit checks on its own source. This commit addresses this by adding all of the same pre-commit checks as are used in exemplar, except for clang-format and CMake linting, since those aren't relevant here. It fixes all of the failed checks and adds pre-commit checking to CI so they don't recur. --- .github/workflows/pre-commit.yml | 78 +++++++++++++++++++ .gitignore | 1 - .pre-commit-config.yaml | 20 +++++ tools/beman-submodule/beman-submodule | 2 +- tools/beman-tidy/README.md | 37 +++++---- tools/beman-tidy/beman_tidy/lib/pipeline.py | 2 +- tools/beman-tidy/docs/dev-guide.md | 74 +++++++++++------- .../readme/data/invalid/invalid-badge-v1.md | 4 +- .../readme/data/invalid/invalid-badge-v2.md | 4 +- .../readme/data/invalid/invalid-badge-v3.md | 3 +- .../data/invalid/invalid-status-line-v1.md | 3 +- .../data/invalid/invalid-status-line-v2.md | 3 +- .../data/invalid/invalid-status-line-v3.md | 2 +- .../readme/data/invalid/invalid-title-v1.md | 2 +- .../readme/data/invalid/invalid-title-v2.md | 3 +- .../readme/data/invalid/invalid-title-v3.md | 4 +- .../readme/data/invalid/invalid-title-v4.md | 3 +- .../readme/data/valid/README-v1.md | 3 +- .../readme/data/valid/README-v2.md | 2 + .../readme/data/valid/README-v3.md | 3 + .../readme/data/valid/README-v4.md | 2 + 21 files changed, 188 insertions(+), 67 deletions(-) create mode 100644 .github/workflows/pre-commit.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..96468311 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,78 @@ +name: Lint Check (pre-commit) + +on: + # We have to use pull_request_target here as pull_request does not grant + # enough permission for reviewdog + pull_request_target: + push: + branches: + - main + +jobs: + pre-commit-push: + name: Pre-Commit check on Push + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + 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: + name: Pre-Commit check on PR + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request_target' }} + + permissions: + contents: read + checks: write + issues: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # pull_request_target checkout the base of the repo + # We need to checkout the actual pr to lint the changes. + - name: Checkout pr + run: gh pr checkout ${{ github.event.number }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + 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 + uses: reviewdog/action-suggester@v1 + if: ${{ failure() && steps.run-pre-commit.conclusion == 'failure' }} + with: + tool_name: pre-commit + level: warning + reviewdog_flags: "-fail-level=error" diff --git a/.gitignore b/.gitignore index 7389e9e9..b7cdbb52 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,3 @@ beman_tidy.egg-info/ *.egg-info/ build/ dist/ - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..9e8c4529 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + + # Markdown linting + # Config file: .markdownlint.yaml + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.42.0 + hooks: + - id: markdownlint + + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 9fe09aad..0553dcad 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -47,7 +47,7 @@ def parse_beman_submodule_file(path): fail() return BemanSubmodule( Path(path).resolve().parent, - config['beman_submodule']['remote'], + config['beman_submodule']['remote'], config['beman_submodule']['commit_hash']) def get_beman_submodule(path: str | Path): diff --git a/tools/beman-tidy/README.md b/tools/beman-tidy/README.md index 19fae9f5..c01045e8 100644 --- a/tools/beman-tidy/README.md +++ b/tools/beman-tidy/README.md @@ -6,10 +6,12 @@ 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). +`beman-tidy` is a tool used to check and apply +[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 checks will not support the `--fix-inplace` flag in the first iteration. +Note: `2025-06-07`: In order to make the best and quickly use of the tool in the entire organization, most of the +checks will not support the `--fix-inplace` flag in the first iteration. ## Installation @@ -18,8 +20,8 @@ Note: `2025-06-07`: In order to make the best and quickly use of the tool in the - You can use beman-tidy as a pre-commit hook or install it on your system using `pipx` ```shell -$ uv build -$ pipx install path/to/wheel +uv build +pipx install path/to/wheel ```
@@ -49,7 +51,7 @@ usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verb ## Usage -* Display help: +- Display help: ```shell $ uv run beman-tidy --help @@ -69,8 +71,7 @@ options: --checks CHECKS array of checks to run ``` -* Run beman-tidy on the exemplar repository **(default: dry-run mode)** - +- Run beman-tidy on the exemplar repository **(default: dry-run mode)** ```shell # dry-run, require-all, non-verbose @@ -92,23 +93,24 @@ Note: RECOMMENDATIONs are not included (--require-all NOT set). ``` or verbose mode: + ```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 + check [RECOMMENDATION][README.TITLE] ... PASSED Running check [REQUIREMENT][README.BADGES] ... - check [REQUIREMENT][README.BADGES] ... PASSED + check [REQUIREMENT][README.BADGES] ... PASSED Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + check [RECOMMENDATION][README.LIBRARY_STATUS] ... 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 + check [RECOMMENDATION][DIRECTORY.SOURCES] ... FAILED beman-tidy pipeline finished. @@ -120,21 +122,22 @@ Coverage REQUIREMENT: 100.0% (1/1 checks passed). Coverage RECOMMENDATION: 66.67% (2/3 checks passed). ``` +```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 + check [RECOMMENDATION][README.TITLE] ... PASSED Running check [REQUIREMENT][README.BADGES] ... - check [REQUIREMENT][README.BADGES] ... PASSED + check [REQUIREMENT][README.BADGES] ... PASSED Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED + check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED Running check [RECOMMENDATION][DIRECTORY.SOURCES] ... - check [RECOMMENDATION][DIRECTORY.SOURCES] ... PASSED + check [RECOMMENDATION][DIRECTORY.SOURCES] ... PASSED beman-tidy pipeline finished. @@ -146,10 +149,10 @@ Coverage REQUIREMENT: 100.0% (1/1 checks passed). Coverage RECOMMENDATION: 100.0% (3/3 checks passed). ``` -* Run beman-tidy on the exemplar repository (fix issues in-place): +- Run beman-tidy on the exemplar repository (fix issues in-place): ```shell -$ uv run beman-tidy path/to/exemplar --fix-inplace --verbose +uv run beman-tidy path/to/exemplar --fix-inplace --verbose ``` ## beman-tidy Development diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index 7d661b79..5467082c 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -73,7 +73,7 @@ def run_pipeline_helper(): implemented_checks = get_registered_beman_standard_checks() all_checks = beman_standard_check_config - + cnt_passed = { "REQUIREMENT": 0, "RECOMMENDATION": 0, diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 58839503..f737579d 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -10,6 +10,7 @@ Expected Development Flow: * Commit the changes. Requirements: + * `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. * `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). * `beman-tidy` must have `verbose` and `non-verbose` modes. Default is `non-verbose`. @@ -17,39 +18,47 @@ Requirements: * `beman-tidy` must detect types of checks: failed, passed, skipped (not implemented) and print the summary/coverage. Limitations: + * `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. -* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard is not stable. Thus, the tool itself may be unstable. +* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard + is not stable. Thus, the tool itself may be unstable. ## Tree structure * `README.md`: The public documentation for the `beman-tidy` tool. * `docs/`: The internal documentation. * `beman_tidy/`: The package/production code for the tool. - * `beman_tidy/cli.py`: The CLI / entry point for the tool. - * `beman_tidy/lib/`: The library for the tool. - * `beman_tidy/lib/checks/`: The checks for the tool. - * `beman_tidy/lib/pipeline.py`: The checks pipeline for the `beman-tidy` tool. - * `beman_tidy/.beman-standard.yml`: Stable (offline)version of the standard. + * `beman_tidy/cli.py`: The CLI / entry point for the tool. + * `beman_tidy/lib/`: The library for the tool. + * `beman_tidy/lib/checks/`: The checks for the tool. + * `beman_tidy/lib/pipeline.py`: The checks pipeline for the `beman-tidy` tool. + * `beman_tidy/.beman-standard.yml`: Stable (offline)version of the standard. * `tests/`: Unit tests for the tool. - * Structure is similar to the `beman_tidy/` directory. - * `pytest` is used for testing. + * Structure is similar to the `beman_tidy/` directory. + * `pytest` is used for testing. ## Adding 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). - * `[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#L68) if not already implemented. Checks for TODOs in `load_beman_standard_config()`. + * `[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#L68) + 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]` Use an appropiate 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") - class ReadmeTitleCheck(ReadmeBaseCheck): - ``` -* `[mandatory]` Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., `from .checks.beman_standard.readme import ReadmeTitleCheck`). + * `[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") + class ReadmeTitleCheck(ReadmeBaseCheck): + ``` + +* `[mandatory]` Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., + `from .checks.beman_standard.readme import ReadmeTitleCheck`). * `[mandatory]` Add tests for the check to the `tests/beman_standard/` directory. More in [Writing Tests](#writing-tests). -* `[optional]` Updates docs if needed in `README.md` and `docs/dev-guide.md` files. +* `[optional]` Updates docs if needed in `README.md` and `docs/dev-guide.md` files. * `[optional]` Update the `beman_tidy/cli.py` file if the public API has changed. Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). @@ -59,8 +68,8 @@ Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://g Run the linter on the beman-tidy's codebase: ```shell -$ uv run ruff check --diff -$ uv run ruff check --fix +uv run ruff check --diff +uv run ruff check --fix ``` ## Testing @@ -90,23 +99,30 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI ### Writing Tests -* `tests/lib/checks/beman_standard//test_.py`: The test file for the `` check. +* `tests/lib/checks/beman_standard//test_.py`: The test file for the `` + 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()`. + * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the function is + `test__README_TITLE__invalid()`. * `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/`. - * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in `tests/lib/checks/beman_standard/readme/data/invalid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "fix_invalid"` the data may use both `valid` and `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` (which are not tracked by git). + * e.g., for `check_category = "readme"` and `test_case_name = "valid"` the data is in + `tests/lib/checks/beman_standard/readme/data/valid/`. + * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in + `tests/lib/checks/beman_standard/readme/data/invalid/`. + * e.g., for `check_category = "readme"` and `test_case_name = "fix_invalid"` the data may use both `valid` and + `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` + (which are not tracked by git). * Default setup / mocks: * `repo_info`: The repository information (e.g., path, name, etc.). Mocked with hardcoded values of `beman.exemplar`. - * `beman_standard_check_config`: The Beman Standard configuration file. Actual load of the `.beman-standard.yml` file. + * `beman_standard_check_config`: The Beman Standard configuration file. Actual load of the `.beman-standard.yml` + file. * Always add at least 3 test cases for each check. * `valid`: The test case for the valid case. * `invalid`: The test case for the invalid case. - * `fix_invalid`: 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. - + * `fix_invalid`: 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. ## Changing dependencies diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md index c2a3c135..d35e495f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md @@ -5,12 +5,12 @@ ![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) + **Purpose**: `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: typos in badges. - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md index ec8f9cee..b73d201d 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md @@ -5,13 +5,11 @@ ![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) + **Purpose**: `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: invalid badge display text. - - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md index dfdd4e2f..32c5ecaf 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md @@ -5,12 +5,11 @@ ![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) + **Purpose**: `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: invalid badge URL. - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md index aa46bddb..efce73e1 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md @@ -1,10 +1,11 @@ -## beman.exemplar: A Beman Library Exemplar +# 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) + **Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md index 6d3f668f..fdec922c 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md @@ -5,11 +5,12 @@ ![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) + **Purpose**: `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) This is NOT a valid README.md according to the Beman Standard: the library status line has typos. - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md index af1629a1..64ca1ece 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md @@ -5,6 +5,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) + **Purpose**: `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). @@ -15,4 +16,3 @@ **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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md index 573d65b4..62e492a4 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md @@ -5,11 +5,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) + **Purpose**: `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: missing beman.exemplar. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md index b992d38e..45048301 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md @@ -5,12 +5,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) + **Purpose**: `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: missing : - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md index 0f4eda26..aac812de 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md @@ -5,12 +5,12 @@ ![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) + **Purpose**: `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: wrong library name. - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md index 0f4eda26..ef484ace 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md @@ -5,12 +5,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) + **Purpose**: `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: wrong library name. - diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md index 35bab355..fb9a816e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md @@ -5,13 +5,14 @@ ![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) + **Purpose**: `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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md index 5f79a535..1b8c4e04 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md @@ -5,12 +5,14 @@ ![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) + **Purpose**: `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) + 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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md index e341a6b4..be64207e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md @@ -5,12 +5,15 @@ ![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) + **Purpose**: `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) + 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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md index ae00d264..3fd85b14 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md @@ -5,12 +5,14 @@ ![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) + **Purpose**: `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) + 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. From 14ea1d7bd71fda2b42f055d3a05b64140447a84a Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Wed, 25 Jun 2025 12:39:25 +0100 Subject: [PATCH 221/371] Fix duplicative CI runs when updating a pull request When updating the branch associated with a pull request, previously, CI would trigger twice: once for the update to the branch, and another time for the update to the pull request itself. This commit addresses the issue by restricting CI runs for updates to branches to those that update the main branch itself. --- .github/workflows/beman-submodule.yml | 2 ++ .github/workflows/beman-tidy.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/beman-submodule.yml b/.github/workflows/beman-submodule.yml index d18dd7fa..8435086c 100644 --- a/.github/workflows/beman-submodule.yml +++ b/.github/workflows/beman-submodule.yml @@ -4,6 +4,8 @@ name: beman-submodule tests on: push: + branches: + - main pull_request: workflow_dispatch: diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index 4fc73693..d5611f8c 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -4,6 +4,8 @@ name: beman-tidy tests on: push: + branches: + - main pull_request: workflow_dispatch: From d5d83c78d733474c420c4d7cd9cc200490cc1b15 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Wed, 25 Jun 2025 16:23:50 +0100 Subject: [PATCH 222/371] beman-submodule: Fix beman-submodule update --remote Previously, this command did not update the commit_hash in the .beman_submodule file when updating the beman submodule to the latest version. This commit fixes the bug and adds reproducing tests. --- tools/beman-submodule/beman-submodule | 5 +- .../test/test_beman_submodule.py | 98 +++++++++++++++---- 2 files changed, 83 insertions(+), 20 deletions(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 0553dcad..2558e559 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -105,6 +105,9 @@ def beman_submodule_status(beman_submodule): def beman_submodule_update(beman_submodule, remote): tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, remote) tmp_path = Path(tmpdir.name) + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmp_path) shutil.rmtree(beman_submodule.dirpath) @@ -112,7 +115,7 @@ def beman_submodule_update(beman_submodule, remote): with open(submodule_path, 'w') as f: f.write('[beman_submodule]\n') f.write(f'remote={beman_submodule.remote}\n') - f.write(f'commit_hash={beman_submodule.commit_hash}\n') + f.write(f'commit_hash={sha_process.stdout.strip()}\n') shutil.rmtree(tmp_path / '.git') shutil.copytree(tmp_path, beman_submodule.dirpath) diff --git a/tools/beman-submodule/test/test_beman_submodule.py b/tools/beman-submodule/test/test_beman_submodule.py index 5010b8a7..746e08d1 100644 --- a/tools/beman-submodule/test/test_beman_submodule.py +++ b/tools/beman-submodule/test/test_beman_submodule.py @@ -202,20 +202,50 @@ def test_update_command_no_paths(): tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') - sha_process = subprocess.run( + orig_sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + orig_sha = orig_sha_process.stdout.strip() + parent_sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, cwd=tmpdir.name) - sha = sha_process.stdout.strip() + parent_sha = parent_sha_process.stdout.strip() + parent_parent_sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + parent_parent_sha = parent_parent_sha_process.stdout.strip() subprocess.run( - ['git', 'reset', '--hard', sha], capture_output=True, check=True, + ['git', 'reset', '--hard', parent_parent_sha], capture_output=True, check=True, + cwd=tmpdir.name) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + subprocess.run( + ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, cwd=tmpdir.name) with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'w') as f: - f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n') with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'w') as f: - f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') - beman_submodule.update_command(tmpdir.name, None) + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n') + beman_submodule.update_command(False, None) + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n' + with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n' + subprocess.run( + ['git', 'reset', '--hard', parent_sha], capture_output=True, check=True, + cwd=tmpdir.name) + assert beman_submodule.directory_compare( + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + assert beman_submodule.directory_compare( + tmpdir.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + subprocess.run( + ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, + cwd=tmpdir.name) + beman_submodule.update_command(True, None) + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={orig_sha}\n' + with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={orig_sha}\n' assert beman_submodule.directory_compare( tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) assert beman_submodule.directory_compare( @@ -225,28 +255,58 @@ def test_update_command_no_paths(): def test_update_command_with_path(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() - tmpdir_copy1 = tempfile.TemporaryDirectory() - shutil.copytree(tmpdir.name, tmpdir_copy1.name, dirs_exist_ok=True) original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') - sha_process = subprocess.run( + orig_sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + orig_sha = orig_sha_process.stdout.strip() + parent_sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, cwd=tmpdir.name) - sha = sha_process.stdout.strip() + parent_sha = parent_sha_process.stdout.strip() + parent_parent_sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + parent_parent_sha = parent_parent_sha_process.stdout.strip() subprocess.run( - ['git', 'reset', '--hard', sha], capture_output=True, check=True, + ['git', 'reset', '--hard', parent_parent_sha], capture_output=True, check=True, + cwd=tmpdir.name) + tmpdir_parent_parent_copy = tempfile.TemporaryDirectory() + shutil.copytree(tmpdir.name, tmpdir_parent_parent_copy.name, dirs_exist_ok=True) + beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'bar') + subprocess.run( + ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, cwd=tmpdir.name) with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'w') as f: - f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n') with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'w') as f: - f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n') - beman_submodule.update_command(tmpdir.name, 'foo') + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n') + beman_submodule.update_command(False, 'foo') + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n' + with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n' + subprocess.run( + ['git', 'reset', '--hard', parent_sha], capture_output=True, check=True, + cwd=tmpdir.name) + assert beman_submodule.directory_compare( + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + assert beman_submodule.directory_compare( + tmpdir_parent_parent_copy.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + subprocess.run( + ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, + cwd=tmpdir.name) + beman_submodule.update_command(True, 'foo') + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={orig_sha}\n' + with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'r') as f: + assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n' assert beman_submodule.directory_compare( tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) assert beman_submodule.directory_compare( - tmpdir_copy1.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + tmpdir_parent_parent_copy.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) os.chdir(original_cwd) def test_add_command(): From 5c4ae0c5d4c837f8b91d8b4a51640608f71b1a83 Mon Sep 17 00:00:00 2001 From: rishyak Date: Sat, 28 Jun 2025 20:02:31 -0400 Subject: [PATCH 223/371] refactor: using existing logic to check top-level CML - previously, we were hand-rolling the checks for the existence of the file, and whether or not the file is empty - FileBaseCheck already provides these tests --- .../lib/checks/beman_standard/toplevel.py | 33 +++---------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index cf83a0f6..7ad6d394 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.base_check import BaseCheck +from .cmake import CMakeBaseCheck from ..system.registry import register_beman_standard_check # [TOPLEVEL.*] checks category. @@ -10,42 +10,19 @@ # Note: ToplevelBaseCheck is not a registered check! -class ToplevelBaseCheck(BaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - -@register_beman_standard_check("TOPLEVEL.CMAKE") -class ToplevelCmakeCheck(ToplevelBaseCheck): +@register_beman_standard_check(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): - """ - self.config["value"] contains the CMake file name. - """ - self.path = self.repo_path / self.config["value"] - assert self.config["value"].endswith(".txt") - - if not self.path.exists(): - self.log("The top-level CMake file does not exist.") - return False - - try: - with open(self.path, 'r') as file: - if len(file.read()) == 0: - self.log("The top-level CMake file is empty.") - return False - except Exception: - self.log("Failed to read the top-level CMake file.") - return False - - return True + return super().pre_check() def fix(self): # TODO: Implement the fix. pass -# TODO TOPLEVEL.LICENSE - use FileBaseCheck +# TODO TOPLEVEL.LICENSE - use FileBaseCheck # TODO TOPLEVEL.README - use ReadmeBaseCheck From dc3effcc42d11ebb37d97b9d1919b11a3fa61bdc Mon Sep 17 00:00:00 2001 From: rishyak Date: Sat, 28 Jun 2025 20:31:57 -0400 Subject: [PATCH 224/371] fix: remove errant print --- .../beman_tidy/lib/checks/base/directory_base_check.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py index 12b0e163..80409a36 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py @@ -14,7 +14,6 @@ class DirectoryBaseCheck(BaseCheck): def __init__(self, repo_info, beman_standard_check_config, relative_path): super().__init__(repo_info, beman_standard_check_config) - print(repo_info) # set path - e.g. "src/beman/exemplar" self.path = self.repo_path / relative_path From b1b955a832860432ddf8953afcd066944441a4b3 Mon Sep 17 00:00:00 2001 From: rishyak Date: Sat, 28 Jun 2025 20:40:49 -0400 Subject: [PATCH 225/371] fix: use correct python shebang - https://peps.python.org/pep-0394/ --- tools/beman-tidy/beman_tidy/cli.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py | 2 +- .../beman_tidy/lib/checks/base/directory_base_check.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py | 2 +- .../beman_tidy/lib/checks/beman_standard/directory.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py | 2 +- .../beman-tidy/beman_tidy/lib/checks/beman_standard/general.py | 3 +-- .../beman-tidy/beman_tidy/lib/checks/beman_standard/license.py | 2 +- .../beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py | 2 +- .../beman-tidy/beman_tidy/lib/checks/beman_standard/release.py | 2 +- .../beman_tidy/lib/checks/beman_standard/toplevel.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/system/git.py | 2 +- tools/beman-tidy/beman_tidy/lib/checks/system/registry.py | 2 +- tools/beman-tidy/beman_tidy/lib/pipeline.py | 2 +- tools/beman-tidy/beman_tidy/lib/utils/git.py | 2 +- tools/beman-tidy/beman_tidy/lib/utils/string.py | 2 +- tools/beman-tidy/beman_tidy/lib/utils/terminal.py | 2 +- tools/beman-tidy/tests/conftest.py | 2 +- .../tests/lib/checks/beman_standard/readme/conftest.py | 2 +- .../tests/lib/checks/beman_standard/readme/test_readme.py | 2 +- tools/beman-tidy/tests/utils/conftest.py | 2 +- tools/beman-tidy/tests/utils/directory_testcase_runners.py | 2 +- tools/beman-tidy/tests/utils/file_testcase_runners.py | 2 +- 25 files changed, 25 insertions(+), 26 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/cli.py b/tools/beman-tidy/beman_tidy/cli.py index 7ae1c4d2..a1211336 100755 --- a/tools/beman-tidy/beman_tidy/cli.py +++ b/tools/beman-tidy/beman_tidy/cli.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py index 1cb45b41..45d47023 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from abc import ABC, abstractmethod diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py index 80409a36..d43a39fe 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from abc import abstractmethod diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py index e816d91a..d9fc0575 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from abc import abstractmethod diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py index 78c416f9..1f7a2855 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.file_base_check import FileBaseCheck diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py index 956cc13d..6868f23e 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # [CPP.*] checks category. diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index a5f6c926..2f029d4b 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.directory_base_check import DirectoryBaseCheck diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py index 183e8977..b66e8bec 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # [FILE.*] checks category. diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py index 87cd7496..d0847539 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py @@ -1,5 +1,4 @@ - -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO LIBRARY.NAMES diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 51e96a77..762e95b4 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.file_base_check import FileBaseCheck diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 535b64b2..96eb2031 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import re diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py index bc4403b5..6c2f59b1 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # [RELEASE.*] checks category. diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 7ad6d394..412bc581 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .cmake import CMakeBaseCheck diff --git a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py index 31161b17..da35b466 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import sys diff --git a/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py b/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py index 825c2cad..d4cf5d6c 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from typing import Dict, Type, List diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index 5467082c..59a8d938 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import sys diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index 6ef8786b..c0a6cc7a 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import sys diff --git a/tools/beman-tidy/beman_tidy/lib/utils/string.py b/tools/beman-tidy/beman_tidy/lib/utils/string.py index 756921bd..2d425677 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/string.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/string.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import re diff --git a/tools/beman-tidy/beman_tidy/lib/utils/terminal.py b/tools/beman-tidy/beman_tidy/lib/utils/terminal.py index b3fe87ae..6ca2c277 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/terminal.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/terminal.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import subprocess diff --git a/tools/beman-tidy/tests/conftest.py b/tools/beman-tidy/tests/conftest.py index 1d231042..0e380f4c 100644 --- a/tools/beman-tidy/tests/conftest.py +++ b/tools/beman-tidy/tests/conftest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import pytest diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py index 8aca7010..7277ec85 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import pytest diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 5a0f3f72..37bf92bb 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import pytest diff --git a/tools/beman-tidy/tests/utils/conftest.py b/tools/beman-tidy/tests/utils/conftest.py index 87e4fb85..71d82c06 100644 --- a/tools/beman-tidy/tests/utils/conftest.py +++ b/tools/beman-tidy/tests/utils/conftest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import pytest diff --git a/tools/beman-tidy/tests/utils/directory_testcase_runners.py b/tools/beman-tidy/tests/utils/directory_testcase_runners.py index 9b1d2853..f42e4740 100644 --- a/tools/beman-tidy/tests/utils/directory_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/directory_testcase_runners.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # TODO: Implement directory testcase runners diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index b95839cc..0c7456f4 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import os From 2ffc3c28602c6f7466f8c0bc3f12aeae6ec0756c Mon Sep 17 00:00:00 2001 From: rishyak Date: Sat, 28 Jun 2025 21:29:55 -0400 Subject: [PATCH 226/371] feat: better code coverage reporting with better formatting - Adds yellow color status for partial coverage - Implements consistent decimal formatting for percentages - Extracts color calculation logic to dedicated function - Adding total coverage metrics when --require-all is set This makes it easier to quickly assess code coverage status with clear visual indicators and consistent numerical presentation. --- tools/beman-tidy/beman_tidy/lib/pipeline.py | 26 +++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index 59a8d938..bf70783d 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -126,16 +126,34 @@ def run_pipeline_helper(): # Always print the coverage. coverage_requirement = round(cnt_passed['REQUIREMENT'] / cnt_implemented_checks['REQUIREMENT'] * 100, 2) coverage_recommendation = round(cnt_passed['RECOMMENDATION'] / cnt_implemented_checks['RECOMMENDATION'] * 100, 2) - total_coverage = round((cnt_passed['REQUIREMENT'] + cnt_passed['RECOMMENDATION']) / (cnt_implemented_checks['REQUIREMENT'] + cnt_implemented_checks['RECOMMENDATION']) * 100, 2) + total_passed = cnt_passed['REQUIREMENT'] + cnt_passed['RECOMMENDATION'] + total_implemented = cnt_implemented_checks['REQUIREMENT'] + cnt_implemented_checks['RECOMMENDATION'] + total_coverage = round((total_passed) / (total_implemented) * 100, 2) print( - f"\n{green_color if coverage_requirement == 100 else red_color}Coverage REQUIREMENT: {coverage_requirement}% ({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']}/{cnt_implemented_checks['REQUIREMENT']} checks passed).{no_color}") if args.require_all: print( - f"{green_color if coverage_recommendation == 100 else red_color}Coverage RECOMMENDATION: {coverage_recommendation}% ({cnt_passed['RECOMMENDATION']}/{cnt_implemented_checks['RECOMMENDATION']} checks passed).{no_color}") + 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) - sys.stdout.flush() return total_cnt_failed + + +def __calculate_coverage_color(cov): + """ + Returns the colour for the coverage print based on severity + Green for 100% + Red for 0% + Yellow for anything else + """ + if cov == 100: + return green_color + elif cov == 0: + return red_color + else: + return yellow_color From 2e8c981f91cb50366c8cc804978e54fe94756547 Mon Sep 17 00:00:00 2001 From: rishyak Date: Sat, 28 Jun 2025 22:51:51 -0400 Subject: [PATCH 227/371] style: mass format --- tools/beman-tidy/beman_tidy/cli.py | 3 +- .../beman_tidy/lib/checks/base/base_check.py | 24 +++-- .../lib/checks/base/file_base_check.py | 6 +- .../lib/checks/beman_standard/cmake.py | 1 + .../lib/checks/beman_standard/directory.py | 8 +- .../lib/checks/beman_standard/license.py | 1 + .../lib/checks/beman_standard/readme.py | 16 ++-- .../beman_tidy/lib/checks/system/git.py | 6 +- .../beman_tidy/lib/checks/system/registry.py | 2 + tools/beman-tidy/beman_tidy/lib/pipeline.py | 75 +++++++++++----- tools/beman-tidy/beman_tidy/lib/utils/git.py | 6 +- .../beman-tidy/beman_tidy/lib/utils/string.py | 10 ++- .../beman_tidy/lib/utils/terminal.py | 5 +- tools/beman-tidy/tests/conftest.py | 4 +- .../checks/beman_standard/readme/conftest.py | 1 + .../beman_standard/readme/test_readme.py | 53 +++++++---- .../tests/utils/file_testcase_runners.py | 87 ++++++++++++------- 17 files changed, 210 insertions(+), 98 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/cli.py b/tools/beman-tidy/beman_tidy/cli.py index a1211336..de648110 100755 --- a/tools/beman-tidy/beman_tidy/cli.py +++ b/tools/beman-tidy/beman_tidy/cli.py @@ -62,7 +62,8 @@ def main(): ) failed_checks = run_checks_pipeline( - checks_to_run, args, beman_standard_check_config) + checks_to_run, args, beman_standard_check_config + ) sys.exit(failed_checks) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py index 45d47023..f3431ab6 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py @@ -20,24 +20,30 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): """ # check name - e.g. "README.TITLE" - self.name = name if name is not None else get_beman_standard_check_name_by_class( - self.__class__) - assert self.name is not None, f"Check name not found for class: {self.__class__.__name__}" + self.name = ( + name + if name is not None + else get_beman_standard_check_name_by_class(self.__class__) + ) + assert self.name is not None, ( + f"Check name not found for class: {self.__class__.__name__}" + ) # save the check config self.config = beman_standard_check_config[self.name] # set type - e.g. "REQUIREMENT" or "RECOMMENDATION" self.type = beman_standard_check_config[self.name]["type"] - assert self.type in [ - 'REQUIREMENT', 'RECOMMENDATION'], f"Invalid check type: {self.type} for check = {self.name}." + 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"] 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' + self.log_level = "ERROR" if self.type == "REQUIREMENT" else "WARNING" self.log_enabled = False # set repo info @@ -51,7 +57,9 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): assert self.library_name is not None # set beman library maturity model - beman_library_maturity_model = beman_standard_check_config["README.LIBRARY_STATUS"] + beman_library_maturity_model = beman_standard_check_config[ + "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"] @@ -108,4 +116,4 @@ def log(self, message, enabled=True): """ if self.log_enabled and enabled: - print(f'[{self.log_level:<15}][{self.name:<25}]: {message}') + print(f"[{self.log_level:<15}][{self.name:<25}]: {message}") diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py index d9fc0575..bea8eeee 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py @@ -59,7 +59,7 @@ def read(self): Read the file content. """ try: - with open(self.path, 'r') as file: + with open(self.path, "r") as file: return file.read() except Exception: return "" @@ -69,7 +69,7 @@ def read_lines(self): Read the file content as lines. """ try: - with open(self.path, 'r') as file: + with open(self.path, "r") as file: return file.readlines() except Exception: return [] @@ -85,7 +85,7 @@ def write(self, content): Write the content to the file. """ try: - with open(self.path, 'w') as file: + with open(self.path, "w") as file: file.write(content) except Exception as e: self.log(f"Error writing the file '{self.path}': {e}") diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py index 1f7a2855..49d9d24c 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py @@ -13,6 +13,7 @@ class CMakeBaseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "CMakeLists.txt") + # TODO CMAKE.DEFAULT diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 2f029d4b..d533bb3a 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -4,6 +4,7 @@ from ..base.directory_base_check import DirectoryBaseCheck from ..system.registry import register_beman_standard_check + # [DIRECTORY.*] checks category. class BemanTreeDirectoryCheck(DirectoryBaseCheck): """ @@ -11,7 +12,11 @@ class BemanTreeDirectoryCheck(DirectoryBaseCheck): """ def __init__(self, repo_info, beman_standard_check_config, prefix_path): - super().__init__(repo_info, beman_standard_check_config, f"{prefix_path}/beman/{repo_info['name']}") + super().__init__( + repo_info, + beman_standard_check_config, + f"{prefix_path}/beman/{repo_info['name']}", + ) # TODO DIRECTORY.INTERFACE_HEADERS @@ -26,6 +31,7 @@ class DirectorySourcesCheck(BemanTreeDirectoryCheck): """ Check if the sources directory is src/beman/. """ + def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "src") diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 762e95b4..6eb75ab5 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -13,6 +13,7 @@ class LicenseBaseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "LICENSE") + # TODO LICENSE.APPROVED diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 96eb2031..fcbead60 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -30,7 +30,8 @@ def check(self): regex = rf"^# {re.escape(self.library_name)}: (.*)$" # noqa: F541 if not re.match(regex, first_line): self.log( - f"The first line of the file '{self.path}' is invalid. It should start with '# {self.library_name}: '.") + f"The first line of the file '{self.path}' is invalid. It should start with '# {self.library_name}: '." + ) return False return True @@ -57,11 +58,11 @@ def check(self): 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)]) + 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}") + f"The file '{self.path}' does not contain exactly one of the required badges from {badges}" + ) return False return True @@ -70,6 +71,7 @@ def fix(self): # TODO: Implement the fix. pass + # TODO README.PURPOSE @@ -89,11 +91,11 @@ def check(self): assert len(statuses) == len(self.beman_library_maturity_model) # Check if at least one of the required status values is present. - status_count = len( - [status for status in statuses if self.has_content(status)]) + status_count = len([status for status in statuses if self.has_content(status)]) if status_count != 1: self.log( - f"The file '{self.path}' does not contain exactly one of the required statuses from {statuses}") + f"The file '{self.path}' does not contain exactly one of the required statuses from {statuses}" + ) return False return True diff --git a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py index da35b466..ecc11456 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py @@ -12,8 +12,7 @@ class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): """ 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, "NO_UNSTAGED_CHANGES") def check(self): """ @@ -26,5 +25,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 cannot be applied inplace. Please commit or stash your changes. STOP." + ) sys.exit(1) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py b/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py index d4cf5d6c..cabb8ac2 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py @@ -19,9 +19,11 @@ 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. """ + def decorator(check_class: Type) -> Type: _beman_standard_check_registry[check] = check_class return check_class + return decorator diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index bf70783d..5814e06a 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -36,6 +36,7 @@ def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): """ Helper function to log messages. """ + def log(msg): if args.verbose: print(msg) @@ -46,30 +47,35 @@ def log(msg): @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): - check_instance = check_class( - args.repo_info, beman_standard_check_config) + 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}] ... ") + log(f"Running check [{check_instance.type}][{check_instance.name}] ... ") - 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") + 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" + ) return check_type, True else: - log(f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}FAILED{no_color}\n") + log( + f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}FAILED{no_color}\n" + ) return check_type, False """ Main pipeline. """ + def run_pipeline_helper(): # Internal checks if args.fix_inplace: - run_check(DisallowFixInplaceAndUnstagedChangesCheck, - log_enabled=False) + run_check(DisallowFixInplaceAndUnstagedChangesCheck, log_enabled=False) implemented_checks = get_registered_beman_standard_checks() all_checks = beman_standard_check_config @@ -113,32 +119,59 @@ def run_pipeline_helper(): else: cnt_implemented_checks[check_type] += 1 - return cnt_passed, cnt_failed, cnt_skipped, cnt_implemented_checks, cnt_all_beman_standard_checks + return ( + cnt_passed, + cnt_failed, + cnt_skipped, + cnt_implemented_checks, + cnt_all_beman_standard_checks, + ) log("beman-tidy pipeline started ...\n") - cnt_passed, cnt_failed, cnt_skipped, cnt_implemented_checks, cnt_all_beman_standard_checks = run_pipeline_helper() + ( + cnt_passed, + cnt_failed, + cnt_skipped, + cnt_implemented_checks, + cnt_all_beman_standard_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}") - 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}") + 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}" + ) + 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}" + ) # Always print the coverage. - coverage_requirement = round(cnt_passed['REQUIREMENT'] / cnt_implemented_checks['REQUIREMENT'] * 100, 2) - coverage_recommendation = round(cnt_passed['RECOMMENDATION'] / cnt_implemented_checks['RECOMMENDATION'] * 100, 2) - total_passed = cnt_passed['REQUIREMENT'] + cnt_passed['RECOMMENDATION'] - total_implemented = cnt_implemented_checks['REQUIREMENT'] + cnt_implemented_checks['RECOMMENDATION'] + coverage_requirement = round( + cnt_passed["REQUIREMENT"] / cnt_implemented_checks["REQUIREMENT"] * 100, 2 + ) + coverage_recommendation = round( + cnt_passed["RECOMMENDATION"] / cnt_implemented_checks["RECOMMENDATION"] * 100, 2 + ) + total_passed = cnt_passed["REQUIREMENT"] + cnt_passed["RECOMMENDATION"] + total_implemented = ( + cnt_implemented_checks["REQUIREMENT"] + cnt_implemented_checks["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']}/{cnt_implemented_checks['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}") + 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}") + 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) + total_cnt_failed = cnt_failed["REQUIREMENT"] + ( + cnt_failed["RECOMMENDATION"] if args.require_all else 0 + ) sys.stdout.flush() return total_cnt_failed diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index c0a6cc7a..c397f8ee 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -55,8 +55,7 @@ def get_repo_info(path: str): print(f"The path '{path}' is not inside a valid Git repository.") sys.exit(1) except Exception: - print( - f"An error occurred while getting repository information. Check {path}.") + print(f"An error occurred while getting repository information. Check {path}.") sys.exit(1) @@ -115,8 +114,7 @@ def load_beman_standard_config(path=get_beman_standard_config_path()): elif "default_group" in entry: check_config["default_group"] = entry["default_group"] else: - raise ValueError( - f"Invalid entry in Beman Standard YAML: {entry}") + raise ValueError(f"Invalid entry in Beman Standard YAML: {entry}") beman_standard_check_config[check_name] = check_config diff --git a/tools/beman-tidy/beman_tidy/lib/utils/string.py b/tools/beman-tidy/beman_tidy/lib/utils/string.py index 2d425677..07329da2 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/string.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/string.py @@ -14,7 +14,11 @@ def is_beman_snake_case(name): It must NOT end with a C++ target standard version - e.g. 17, 20, 23, 26, 32, etc. """ - return name[:6] == "beman." and is_snake_case(name[6:]) and not re.match(".*[0-9]+$", name[6:]) + return ( + name[:6] == "beman." + and is_snake_case(name[6:]) + and not re.match(".*[0-9]+$", name[6:]) + ) def match_badges(string): @@ -25,7 +29,9 @@ def match_badges(string): return None badges_str = re.findall(r"!\[[^\]]+\]\([^)]+\)", string) - return [re.match(r"!\[([^\]]+)\]\(([^)]+)\)", badge).groups() for badge in badges_str] + return [ + re.match(r"!\[([^\]]+)\]\(([^)]+)\)", badge).groups() for badge in badges_str + ] def skip_lines(lines, n): diff --git a/tools/beman-tidy/beman_tidy/lib/utils/terminal.py b/tools/beman-tidy/beman_tidy/lib/utils/terminal.py index 6ca2c277..6ba12977 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/terminal.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/terminal.py @@ -12,8 +12,9 @@ def run_command(command, return_stdout=False, cwd=None): """ print(f"Running command: {command} with cwd: {cwd}") if return_stdout: - bin = subprocess.Popen(command, shell=True, - stdout=subprocess.PIPE, cwd=cwd).stdout.read() + bin = subprocess.Popen( + command, shell=True, stdout=subprocess.PIPE, cwd=cwd + ).stdout.read() return bin.decode("utf-8") else: return subprocess.run(command, shell=True, cwd=cwd).returncode diff --git a/tools/beman-tidy/tests/conftest.py b/tools/beman-tidy/tests/conftest.py index 0e380f4c..430a7be8 100644 --- a/tools/beman-tidy/tests/conftest.py +++ b/tools/beman-tidy/tests/conftest.py @@ -25,7 +25,7 @@ def _setup_test_environment(): root_dir = Path(__file__).parent.parent # Add the project root to PYTHONPATH if not already there - if str(root_dir) not in os.environ.get('PYTHONPATH', ''): - os.environ['PYTHONPATH'] = f"{root_dir}:{os.environ.get('PYTHONPATH', '')}" + if str(root_dir) not in os.environ.get("PYTHONPATH", ""): + os.environ["PYTHONPATH"] = f"{root_dir}:{os.environ.get('PYTHONPATH', '')}" yield diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py index 7277ec85..515dc2bd 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py @@ -5,6 +5,7 @@ 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 diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 37bf92bb..1f1b43a5 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -4,14 +4,24 @@ import pytest from pathlib import Path -from tests.utils.file_testcase_runners import file_testcases_run_valid, file_testcases_run_invalid, file_testcases_run_fix_invalid +from tests.utils.file_testcase_runners import ( + file_testcases_run_valid, + file_testcases_run_invalid, + file_testcases_run_fix_invalid, +) + # Actual tested checks. -from beman_tidy.lib.checks.beman_standard.readme import ReadmeTitleCheck, ReadmeBadgesCheck, ReadmeLibraryStatusCheck +from beman_tidy.lib.checks.beman_standard.readme import ( + ReadmeTitleCheck, + ReadmeBadgesCheck, + ReadmeLibraryStatusCheck, +) test_data_prefix = "tests/lib/checks/beman_standard/readme/data" valid_prefix = f"{test_data_prefix}/valid" invalid_prefix = f"{test_data_prefix}/invalid" + def test__README_TITLE__valid(repo_info, beman_standard_check_config): """Test that a valid README.md title passes the check""" valid_readme_paths = [ @@ -25,8 +35,9 @@ def test__README_TITLE__valid(repo_info, beman_standard_check_config): Path(f"{valid_prefix}/README-v4.md"), ] - file_testcases_run_valid(valid_readme_paths, ReadmeTitleCheck, - repo_info, beman_standard_check_config) + file_testcases_run_valid( + valid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + ) def test__README_TITLE__invalid(repo_info, beman_standard_check_config): @@ -39,8 +50,9 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-title-v4.md"), ] - file_testcases_run_invalid(invalid_readme_paths, ReadmeTitleCheck, - repo_info, beman_standard_check_config) + file_testcases_run_invalid( + invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + ) def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): @@ -53,7 +65,8 @@ def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): ] file_testcases_run_fix_invalid( - invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config) + invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + ) def test__README_BADGES__valid(repo_info, beman_standard_check_config): @@ -65,8 +78,9 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config): Path(f"{valid_prefix}/README-v4.md"), ] - file_testcases_run_valid(valid_readme_paths, ReadmeBadgesCheck, - repo_info, beman_standard_check_config) + file_testcases_run_valid( + valid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config + ) def test__README_BADGES__invalid(repo_info, beman_standard_check_config): @@ -78,8 +92,9 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-badge-v3.md"), ] - file_testcases_run_invalid(invalid_readme_paths, ReadmeBadgesCheck, - repo_info, beman_standard_check_config) + file_testcases_run_invalid( + invalid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config + ) @pytest.mark.skip(reason="NOT implemented") @@ -97,8 +112,12 @@ def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): Path(f"{valid_prefix}/README-v4.md"), ] - file_testcases_run_valid(valid_readme_paths, ReadmeLibraryStatusCheck, - repo_info, beman_standard_check_config) + file_testcases_run_valid( + valid_readme_paths, + ReadmeLibraryStatusCheck, + repo_info, + beman_standard_check_config, + ) def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config): @@ -110,8 +129,12 @@ def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config) Path(f"{invalid_prefix}/invalid-status-line-v3.md"), ] - file_testcases_run_invalid(invalid_readme_paths, ReadmeLibraryStatusCheck, - repo_info, beman_standard_check_config) + file_testcases_run_invalid( + invalid_readme_paths, + ReadmeLibraryStatusCheck, + repo_info, + beman_standard_check_config, + ) @pytest.mark.skip(reason="NOT implemented") diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index 0c7456f4..4f71d386 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -4,28 +4,41 @@ import os from pathlib import Path -def file_testcase_run(file_path, check_class, repo_info, beman_standard_check_config, expected_result): + +def file_testcase_run( + file_path, check_class, repo_info, beman_standard_check_config, expected_result +): check_instance = check_class(repo_info, beman_standard_check_config) check_instance.path = Path(file_path) check_instance.log_level = True - assert check_instance.pre_check( - ) is True, f"[{check_instance.__class__.__name__}] pre_check() failed for {file_path}" - assert check_instance.check( - ) is expected_result, f"[{check_instance.__class__.__name__}] check() failed for {file_path}" + assert check_instance.pre_check() is True, ( + f"[{check_instance.__class__.__name__}] pre_check() failed for {file_path}" + ) + assert check_instance.check() is expected_result, ( + f"[{check_instance.__class__.__name__}] check() failed for {file_path}" + ) -def file_testcase_run_valid(file_path, check_class, repo_info, beman_standard_check_config): - file_testcase_run(file_path, check_class, repo_info, - beman_standard_check_config, True) +def file_testcase_run_valid( + file_path, check_class, repo_info, beman_standard_check_config +): + file_testcase_run( + file_path, check_class, repo_info, beman_standard_check_config, True + ) -def file_testcase_run_invalid(file_path, check_class, repo_info, beman_standard_check_config): - file_testcase_run(file_path, check_class, repo_info, - beman_standard_check_config, False) +def file_testcase_run_invalid( + file_path, check_class, repo_info, beman_standard_check_config +): + file_testcase_run( + file_path, check_class, repo_info, beman_standard_check_config, False + ) -def file_testcase_run_fix_invalid(invalid_file_path, check_class, repo_info, beman_standard_check_config): +def file_testcase_run_fix_invalid( + invalid_file_path, check_class, repo_info, beman_standard_check_config +): check_instance = check_class(repo_info, beman_standard_check_config) check_instance.path = Path(f"{invalid_file_path}.delete_me") check_instance.write(invalid_file_path.read_text()) @@ -42,23 +55,39 @@ def file_testcase_run_fix_invalid(invalid_file_path, check_class, repo_info, bem os.remove(f"{invalid_file_path}.delete_me") -def file_testcases_run(file_paths, check_class, repo_info, beman_standard_check_config, expected_result): +def file_testcases_run( + file_paths, check_class, repo_info, beman_standard_check_config, expected_result +): for file_path in file_paths: - file_testcase_run(file_path, check_class, repo_info, - beman_standard_check_config, expected_result) - - -def file_testcases_run_valid(file_paths, check_class, repo_info, beman_standard_check_config): - file_testcases_run(file_paths, check_class, repo_info, - beman_standard_check_config, True) - - -def file_testcases_run_invalid(file_paths, check_class, repo_info, beman_standard_check_config): - file_testcases_run(file_paths, check_class, repo_info, - beman_standard_check_config, False) - - -def file_testcases_run_fix_invalid(invalid_file_paths, check_class, repo_info, beman_standard_check_config): + file_testcase_run( + file_path, + check_class, + repo_info, + beman_standard_check_config, + expected_result, + ) + + +def file_testcases_run_valid( + file_paths, check_class, repo_info, beman_standard_check_config +): + file_testcases_run( + file_paths, check_class, repo_info, beman_standard_check_config, True + ) + + +def file_testcases_run_invalid( + file_paths, check_class, repo_info, beman_standard_check_config +): + file_testcases_run( + file_paths, check_class, repo_info, beman_standard_check_config, False + ) + + +def file_testcases_run_fix_invalid( + invalid_file_paths, check_class, repo_info, beman_standard_check_config +): for invalid_file_path in invalid_file_paths: file_testcase_run_fix_invalid( - invalid_file_path, check_class, repo_info, beman_standard_check_config) + invalid_file_path, check_class, repo_info, beman_standard_check_config + ) From 949d3c44318e24794e4e2bf5c94a1f3a2794e389 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 30 Jun 2025 13:15:29 -0400 Subject: [PATCH 228/371] Disable Markdown linting Due to feedback from Beman developers complaining about the noisiness of the warnings produced by markdownlint, at the 2025-06-30 Beman weekly sync the decision was made to disable Markdown linting by default in exemplar. Unlike in exemplar, this commit removes markdown linting entirely from infra, since infra is not a template. --- .markdownlint.yaml | 10 ---------- .pre-commit-config.yaml | 7 ------- 2 files changed, 17 deletions(-) delete mode 100644 .markdownlint.yaml diff --git a/.markdownlint.yaml b/.markdownlint.yaml deleted file mode 100644 index 21c28494..00000000 --- a/.markdownlint.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md033.md -# Disable inline html linter is needed for
-MD033: false - -# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md013.md -# Conforms to .clang-format ColumnLimit -# Update the comment in .clang-format if we no-longer tie these two column limits. -MD013: - line_length: 119 - code_blocks: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e8c4529..09234118 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,13 +7,6 @@ repos: - id: check-yaml - id: check-added-large-files - # Markdown linting - # Config file: .markdownlint.yaml - - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.42.0 - hooks: - - id: markdownlint - - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: From 54112baa4f5220125d73d6ab766ddb96ffae3030 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 30 Jun 2025 13:19:34 -0400 Subject: [PATCH 229/371] CODEOWNERS: remove @bemanproject/core-reviewers core-reviewers is deprecated. --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 67d9e9ba..856bd532 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @ednolan @neatudarius @rishyak @wusatosi @bemanproject/core-reviewers +* @ednolan @neatudarius @rishyak @wusatosi From 0c768a799a087652224d652eb122a60b34e6c53f Mon Sep 17 00:00:00 2001 From: rishyak Date: Sat, 28 Jun 2025 19:58:03 -0400 Subject: [PATCH 230/371] style: add linting and formatting to pre-commit for python - this will just affect beman-tidy and won't hurt other folders. --- .pre-commit-config.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 09234118..6df26854 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,3 +11,14 @@ repos: rev: v2.3.0 hooks: - id: codespell + + # Python linting and formatting + # config file: ruff.toml (not currently present but add if needed) + # https://docs.astral.sh/ruff/configuration/ + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.1 + hooks: + - id: ruff-check + files: ^tools/beman-tidy/ + - id: ruff-format + files: ^tools/beman-tidy/ From bd918de06df8e98f67608dc5650803ce8ae8c9cf Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Tue, 24 Jun 2025 12:39:04 +0530 Subject: [PATCH 231/371] beman-tidy: implement TOPLEVEL.LICENSE and TOPLEVEL:README Simple checks to ensure that the top-level LICENSE and README files exist and are not empty. --- .../lib/checks/beman_standard/toplevel.py | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 412bc581..5c8ac4cc 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .cmake import CMakeBaseCheck +from ..base.file_base_check import FileBaseCheck +from ..base.readme_base_check import ReadmeBaseCheck from ..system.registry import register_beman_standard_check # [TOPLEVEL.*] checks category. @@ -22,7 +24,57 @@ def fix(self): # TODO: Implement the fix. pass +@register_beman_standard_check("TOPLEVEL.LICENSE") +class ToplevelLicenseCheck(FileBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + self.path = self.repo_path / self.config["file_name"] + + if not self.path.exists(): + self.log("The LICENSE file does not exist.") + return False + + try: + with open(self.path, 'r') as file: + if len(file.read()) == 0: + self.log("The LICENSE file is empty.") + return False + except Exception: + self.log("Failed to read the LICENSE file.") + return False + + return True + + def fix(self): + # TODO: Implement the fix. + pass -# TODO TOPLEVEL.LICENSE - use FileBaseCheck +@register_beman_standard_check("TOPLEVEL.README") +class ToplevelLicenseCheck(ReadmeBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + self.path = self.repo_path / self.config["file_name"] + + if not self.path.exists(): + self.log("The README file does not exist.") + return False + + try: + with open(self.path, 'r') as file: + if len(file.read()) == 0: + self.log("The README file is empty.") + return False + except Exception: + self.log("Failed to read the README file.") + return False + + return True + + def fix(self): + # TODO: Implement the fix. + pass -# TODO TOPLEVEL.README - use ReadmeBaseCheck From ba0d6444bb6f440319fea399e2b31eef43ab85a3 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Tue, 24 Jun 2025 12:43:56 +0530 Subject: [PATCH 232/371] Fix import path. --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 5c8ac4cc..f6f9bbc8 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -3,7 +3,7 @@ from .cmake import CMakeBaseCheck from ..base.file_base_check import FileBaseCheck -from ..base.readme_base_check import ReadmeBaseCheck +from .readme import ReadmeBaseCheck from ..system.registry import register_beman_standard_check # [TOPLEVEL.*] checks category. From 347375fbff6782acd2cd8b14337247265579a479 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 12:40:51 +0530 Subject: [PATCH 233/371] Fixed a copy-paste error. --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index f6f9bbc8..a620a78f 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -52,7 +52,7 @@ def fix(self): pass @register_beman_standard_check("TOPLEVEL.README") -class ToplevelLicenseCheck(ReadmeBaseCheck): +class ToplevelReadmeCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) From 91894bd219572a2722f6c72068d6043052b04052 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 13:07:47 +0530 Subject: [PATCH 234/371] Simplified the `check` implementations. --- .../lib/checks/beman_standard/toplevel.py | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index a620a78f..5db1d1fb 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -30,21 +30,9 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - self.path = self.repo_path / self.config["file_name"] - - if not self.path.exists(): - self.log("The LICENSE file does not exist.") - return False - - try: - with open(self.path, 'r') as file: - if len(file.read()) == 0: - self.log("The LICENSE file is empty.") - return False - except Exception: - self.log("Failed to read the LICENSE file.") - return False - + # 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() return True def fix(self): @@ -57,22 +45,9 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - self.path = self.repo_path / self.config["file_name"] - - if not self.path.exists(): - self.log("The README file does not exist.") - return False - - try: - with open(self.path, 'r') as file: - if len(file.read()) == 0: - self.log("The README file is empty.") - return False - except Exception: - self.log("Failed to read the README file.") - return False - - return True + # 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): # TODO: Implement the fix. From 417f92e0c4b4e3068f583d75a39083640162e8f9 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 13:18:25 +0530 Subject: [PATCH 235/371] Populate more of the dictionary in the config reader. --- tools/beman-tidy/beman_tidy/lib/utils/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index c397f8ee..7f8e3d85 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -99,7 +99,7 @@ def load_beman_standard_config(path=get_beman_standard_config_path()): # TODO: Implement the regex check. pass elif "file_name" in entry: - pass + check_config["file_name"] = entry["file_name"] elif "directory_name" in entry: pass elif "values" in entry: From f8a90b95dd6de31ac14d25448137acfe8b7080c8 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 19:42:07 +0530 Subject: [PATCH 236/371] Add a simple `fix` implementation for the TOPLEVEL.README. --- .../beman_tidy/lib/checks/beman_standard/toplevel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 5db1d1fb..3f5c3793 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -50,6 +50,5 @@ def check(self): return super().pre_check() def fix(self): - # TODO: Implement the fix. - pass + self.log("Please write a README file.") From 9497dc65a8f8fbfdf4a20cd65c714007c0e39005 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 20:02:31 +0530 Subject: [PATCH 237/371] Added in missing path in constructor. --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 3f5c3793..141c0efe 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -27,7 +27,7 @@ def fix(self): @register_beman_standard_check("TOPLEVEL.LICENSE") class ToplevelLicenseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) + super().__init__(repo_info, beman_standard_check_config, "LICENSE") def check(self): # since this class simply checks for the existence of a LICENSE file, From 3e2680107fcba5aa29e49e9b38cc74bd428bb6ed Mon Sep 17 00:00:00 2001 From: Tirthankar Mazumder <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 20:07:02 +0530 Subject: [PATCH 238/371] Update tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../beman_tidy/lib/checks/beman_standard/toplevel.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 141c0efe..9159a53f 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -34,7 +34,6 @@ def check(self): # there's nothing more to do than the default pre-check. return super().pre_check() return True - def fix(self): # TODO: Implement the fix. pass @@ -48,7 +47,5 @@ def check(self): # 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.") - From a671d2189f814f64b95d1f2685a15dd85f141cb4 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 21:42:36 +0530 Subject: [PATCH 239/371] Removed an accidental `return`. --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 9159a53f..ed43f2cc 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -33,7 +33,6 @@ def check(self): # 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() - return True def fix(self): # TODO: Implement the fix. pass From e91ee7ab4378f204e40799f959e51e10e58afea5 Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Sun, 29 Jun 2025 21:48:49 +0530 Subject: [PATCH 240/371] Formatted file, added a little more info to the `fix` function output. --- .../lib/checks/beman_standard/toplevel.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index ed43f2cc..4f64dbaa 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -24,6 +24,7 @@ def fix(self): # TODO: Implement the fix. pass + @register_beman_standard_check("TOPLEVEL.LICENSE") class ToplevelLicenseCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): @@ -33,9 +34,12 @@ def check(self): # 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): - # TODO: Implement the fix. - pass + 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." + ) + @register_beman_standard_check("TOPLEVEL.README") class ToplevelReadmeCheck(ReadmeBaseCheck): @@ -46,5 +50,8 @@ def check(self): # 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.") + self.log( + "Please write a README file. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmemd for the desired format." + ) From 67d58fcc393c87aafe1e92e7a7681a57d45a51df Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 30 Jun 2025 18:33:49 -0400 Subject: [PATCH 241/371] Revert "style: add linting and formatting to pre-commit for python" This reverts commit 0c768a799a087652224d652eb122a60b34e6c53f. This commit passed CI for its pull request but broke CI for main, because the pre-commit CI check only runs on files that differ, whereas the on-merge CI check for main checks all the files in the repository, and some of the files in beman-tidy fail the linter. This commit should be reapplied when `pre-commit run --all-files` succeeds. --- .pre-commit-config.yaml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6df26854..09234118 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,14 +11,3 @@ repos: rev: v2.3.0 hooks: - id: codespell - - # Python linting and formatting - # config file: ruff.toml (not currently present but add if needed) - # https://docs.astral.sh/ruff/configuration/ - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.1 - hooks: - - id: ruff-check - files: ^tools/beman-tidy/ - - id: ruff-format - files: ^tools/beman-tidy/ From 5d151e7cef5c54951174ca8b34c744de74550769 Mon Sep 17 00:00:00 2001 From: rishyak Date: Mon, 30 Jun 2025 18:45:05 -0400 Subject: [PATCH 242/371] ignore F403, add TODO --- tools/beman-tidy/beman_tidy/lib/pipeline.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index 5814e06a..a5d7d408 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -7,15 +7,16 @@ from .checks.system.git import DisallowFixInplaceAndUnstagedChangesCheck # import all the implemented checks. -from .checks.beman_standard.cmake import * # noqa: F401 -from .checks.beman_standard.cpp import * # noqa: F401 -from .checks.beman_standard.directory import * # noqa: F401 -from .checks.beman_standard.file import * # noqa: F401 -from .checks.beman_standard.general import * # noqa: F401 -from .checks.beman_standard.license import * # noqa: F401 -from .checks.beman_standard.readme import * # noqa: F401 -from .checks.beman_standard.release import * # noqa: F401 -from .checks.beman_standard.toplevel import * # noqa: F401 +# TODO: Consider removing F403 from ignored lint checks +from .checks.beman_standard.cmake import * # noqa: F401, F403 +from .checks.beman_standard.cpp import * # noqa: F401, F403 +from .checks.beman_standard.directory import * # noqa: F401, F403 +from .checks.beman_standard.file import * # noqa: F401, F403 +from .checks.beman_standard.general import * # noqa: F401, F403 +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.toplevel import * # noqa: F401, F403 red_color = "\033[91m" green_color = "\033[92m" From 9ba2058f29a6cd73f9ee7b1812c6713c97c1ee66 Mon Sep 17 00:00:00 2001 From: rishyak Date: Mon, 30 Jun 2025 18:51:25 -0400 Subject: [PATCH 243/371] style: add linting and formatting to pre-commit for python - this will just affect beman-tidy and won't hurt other folders. --- .pre-commit-config.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 09234118..6df26854 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,3 +11,14 @@ repos: rev: v2.3.0 hooks: - id: codespell + + # Python linting and formatting + # config file: ruff.toml (not currently present but add if needed) + # https://docs.astral.sh/ruff/configuration/ + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.1 + hooks: + - id: ruff-check + files: ^tools/beman-tidy/ + - id: ruff-format + files: ^tools/beman-tidy/ From 6df8ed3eac7b0558a0312a4dfc2b05ad1b0afb7c Mon Sep 17 00:00:00 2001 From: wermos <63574588+wermos@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:09:55 +0530 Subject: [PATCH 244/371] Use `LicenseBaseCheck` instead of `FileBaseCheck`. --- .../beman_tidy/lib/checks/beman_standard/toplevel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index 4f64dbaa..f4c4ad30 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from .cmake import CMakeBaseCheck -from ..base.file_base_check import FileBaseCheck +from .license import LicenseBaseCheck from .readme import ReadmeBaseCheck from ..system.registry import register_beman_standard_check @@ -26,9 +26,9 @@ def fix(self): @register_beman_standard_check("TOPLEVEL.LICENSE") -class ToplevelLicenseCheck(FileBaseCheck): +class ToplevelLicenseCheck(LicenseBaseCheck): def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "LICENSE") + super().__init__(repo_info, beman_standard_check_config) def check(self): # since this class simply checks for the existence of a LICENSE file, From dafc2a9391d5a11553400087a2811523e79deeeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 3 Jul 2025 21:48:39 +0300 Subject: [PATCH 245/371] Update docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d31a49b..512b4b7c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ 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. +respect the usual structure of a Beman library repository nor The Beman Standard! ## Description From 4b797b602fd69822250d5837de8e2057ed7a623a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 3 Jul 2025 22:48:55 +0300 Subject: [PATCH 246/371] [beman-tidy] Improve dev docs --- tools/beman-tidy/docs/dev-guide.md | 60 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index f737579d..ea009412 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -1,28 +1,5 @@ # Beman Tidy Development Guide -Expected Development Flow: - -* Find a Beman Standard check that is not implemented. -* Add a new entry to the `.beman-standard.yml` file. -* Add a new check to the `lib/checks/beman_standard/` directory (find existing checks for inspiration). -* Add tests for the new check. -* Run the tests. -* Commit the changes. - -Requirements: - -* `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. -* `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). -* `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. - -Limitations: - -* `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. -* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard - is not stable. Thus, the tool itself may be unstable. - ## Tree structure * `README.md`: The public documentation for the `beman-tidy` tool. @@ -32,19 +9,27 @@ Limitations: * `beman_tidy/lib/`: The library for the tool. * `beman_tidy/lib/checks/`: The checks for the tool. * `beman_tidy/lib/pipeline.py`: The checks pipeline for the `beman-tidy` tool. - * `beman_tidy/.beman-standard.yml`: Stable (offline)version of the standard. + * `beman_tidy/.beman-standard.yml`: Stable (offline) version of the standard. * `tests/`: Unit tests for the tool. * Structure is similar to the `beman_tidy/` directory. * `pytest` is used for testing. ## Adding 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). +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). + +
+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)). * `[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#L68) + [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. @@ -55,13 +40,12 @@ Limitations: class ReadmeTitleCheck(ReadmeBaseCheck): ``` -* `[mandatory]` Import the check to the `beman_tidy/lib/pipeline.py` file (e.g., - `from .checks.beman_standard.readme import ReadmeTitleCheck`). * `[mandatory]` Add tests for the check to the `tests/beman_standard/` directory. More in [Writing Tests](#writing-tests). * `[optional]` Updates docs if needed in `README.md` and `docs/dev-guide.md` files. * `[optional]` Update the `beman_tidy/cli.py` file if the public API has changed. -Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). +
+ ## Linting @@ -133,3 +117,19 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI * Run `uv build` to build the wheel. * Run `uv run beman-tidy --help` to check if the new dependency is available. * Commit the changes from `pyproject.toml`, `pylock.toml` and `uv.lock`. + +## Development Notes + +Requirements: + +* `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. +* `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). +* `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. + +Limitations: + +* `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. +* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard + is not stable. Thus, the tool itself may be unstable. From 6c713f640581ee2cb5cf5a79d3c84af05e050882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 3 Jul 2025 22:57:33 +0300 Subject: [PATCH 247/371] [beman-tidy] Add more docs for tests --- .../beman_standard/readme/test_readme.py | 36 ++++++--- .../tests/utils/file_testcase_runners.py | 81 +++++++++++++++++++ 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 1f1b43a5..56e6f33e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -23,7 +23,9 @@ def test__README_TITLE__valid(repo_info, beman_standard_check_config): - """Test that a valid README.md title passes the check""" + """ + Test that a valid README.md title passes the check. + """ valid_readme_paths = [ # Title: # beman.exemplar: A Beman Library Exemplar Path(f"{valid_prefix}/README-v1.md"), @@ -41,7 +43,9 @@ def test__README_TITLE__valid(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""" + """ + Test that an invalid README.md title fails the check. + """ invalid_readme_paths = [ Path(f"{invalid_prefix}/invalid.md"), Path(f"{invalid_prefix}/invalid-title-v1.md"), @@ -56,7 +60,9 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): - """Test that the fix method corrects an invalid README.md title""" + """ + Test that the fix method corrects an invalid README.md title. + """ invalid_readme_paths = [ Path(f"{invalid_prefix}/invalid-title-v1.md"), Path(f"{invalid_prefix}/invalid-title-v2.md"), @@ -70,7 +76,9 @@ def test__README_TITLE__fix_invalid(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""" + """ + Test that a valid README.md badges passes the check. + """ valid_readme_paths = [ Path(f"{valid_prefix}/README-v1.md"), Path(f"{valid_prefix}/README-v2.md"), @@ -84,7 +92,9 @@ def test__README_BADGES__valid(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""" + """ + Test that an invalid README.md badges fails the check. + """ invalid_readme_paths = [ Path(f"{invalid_prefix}/invalid.md"), Path(f"{invalid_prefix}/invalid-badge-v1.md"), @@ -99,12 +109,16 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): @pytest.mark.skip(reason="NOT implemented") def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config): - """Test that the fix method corrects an invalid README.md badges""" + """ + Test that the fix method corrects an invalid README.md badges. + """ pass def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): - """Test that a valid README.md library status passes the check""" + """ + Test that a valid README.md library status passes the check. + """ valid_readme_paths = [ Path(f"{valid_prefix}/README-v1.md"), Path(f"{valid_prefix}/README-v2.md"), @@ -121,7 +135,9 @@ def test__README_LIBRARY_STATUS__valid(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""" + """ + Test that an invalid README.md library status fails the check. + """ invalid_readme_paths = [ Path(f"{invalid_prefix}/invalid.md"), Path(f"{invalid_prefix}/invalid-status-line-v1.md"), @@ -139,5 +155,7 @@ def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config) @pytest.mark.skip(reason="NOT implemented") def test__README_LIBRARY_STATUS__fix_invalid(repo_info, beman_standard_check_config): - """Test that the fix method corrects an invalid README.md library status""" + """ + Test that the fix method corrects an invalid README.md library status. + """ pass diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index 4f71d386..101f3418 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -4,10 +4,29 @@ import os from pathlib import Path +# This file contains the testcase runners for the file-based checks. +# Some of the runners use a single file, while others use multiple files. +# The runners are named: +# - file_testcase_run +# - file_testcase_run_ +# - file_testcases_run_ +# - file_testcase_run_fix_invalid +# - file_testcases_run_fix_invalid + def file_testcase_run( file_path, check_class, repo_info, beman_standard_check_config, expected_result ): + """ + Run a testcase for a file-based check. + + Example: + file_path = "tests/lib/checks/beman_standard/readme/data/valid/README-v1.md" + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + expected_result = True + """ check_instance = check_class(repo_info, beman_standard_check_config) check_instance.path = Path(file_path) check_instance.log_level = True @@ -23,6 +42,11 @@ def file_testcase_run( def file_testcase_run_valid( file_path, check_class, repo_info, beman_standard_check_config ): + """ + Run a testcase for a file-based check. + + Example: Similar to file_testcase_run(), but with expected_result = True. + """ file_testcase_run( file_path, check_class, repo_info, beman_standard_check_config, True ) @@ -31,6 +55,11 @@ def file_testcase_run_valid( def file_testcase_run_invalid( file_path, check_class, repo_info, beman_standard_check_config ): + """ + Run a testcase for a file-based check. + + Example: Similar to file_testcase_run(), but with expected_result = False. + """ file_testcase_run( file_path, check_class, repo_info, beman_standard_check_config, False ) @@ -39,6 +68,16 @@ def file_testcase_run_invalid( def file_testcase_run_fix_invalid( invalid_file_path, check_class, repo_info, beman_standard_check_config ): + """ + Run a testcase for a file-based check, starting with a file that is invalid, + and then fixing it. + + Example: + invalid_file_path = "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md" + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + """ check_instance = check_class(repo_info, beman_standard_check_config) check_instance.path = Path(f"{invalid_file_path}.delete_me") check_instance.write(invalid_file_path.read_text()) @@ -58,6 +97,11 @@ def file_testcase_run_fix_invalid( def file_testcases_run( file_paths, check_class, repo_info, beman_standard_check_config, expected_result ): + """ + Run multiple testcases for a file-based check. + + Example: Similar to file_testcase_run(), but with multiple file_paths. + """ for file_path in file_paths: file_testcase_run( file_path, @@ -71,6 +115,18 @@ def file_testcases_run( def file_testcases_run_valid( file_paths, check_class, repo_info, beman_standard_check_config ): + """ + Run multiple testcases for a file-based check. + + Example: + file_paths = [ + "tests/lib/checks/beman_standard/readme/data/valid/README-v1.md", + "tests/lib/checks/beman_standard/readme/data/valid/README-v2.md", + ] + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + """ file_testcases_run( file_paths, check_class, repo_info, beman_standard_check_config, True ) @@ -79,6 +135,18 @@ def file_testcases_run_valid( def file_testcases_run_invalid( file_paths, check_class, repo_info, beman_standard_check_config ): + """ + Run multiple testcases for a file-based check. + + Example: + file_paths = [ + "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md", + "tests/lib/checks/beman_standard/readme/data/invalid/README-v2.md", + ] + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + """ file_testcases_run( file_paths, check_class, repo_info, beman_standard_check_config, False ) @@ -87,6 +155,19 @@ def file_testcases_run_invalid( def file_testcases_run_fix_invalid( invalid_file_paths, check_class, repo_info, beman_standard_check_config ): + """ + Run multiple testcases for a file-based check, for each file starting with a file that is invalid, + and then fixing it. + + Example: + invalid_file_paths = [ + "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md", + "tests/lib/checks/beman_standard/readme/data/invalid/README-v2.md", + ] + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + """ for invalid_file_path in invalid_file_paths: file_testcase_run_fix_invalid( invalid_file_path, check_class, repo_info, beman_standard_check_config From 4c06175351c4ab050a81231eed5195a56ea23d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 3 Jul 2025 23:02:38 +0300 Subject: [PATCH 248/371] [beman-tidy] Sanitize test data --- .../beman_standard/readme/data/invalid/invalid-badge-v1.md | 2 +- .../beman_standard/readme/data/invalid/invalid-badge-v2.md | 2 +- .../beman_standard/readme/data/invalid/invalid-badge-v3.md | 2 +- .../readme/data/invalid/invalid-status-line-v1.md | 2 +- .../readme/data/invalid/invalid-status-line-v2.md | 2 +- .../readme/data/invalid/invalid-status-line-v3.md | 2 +- .../beman_standard/readme/data/invalid/invalid-title-v1.md | 2 +- .../beman_standard/readme/data/invalid/invalid-title-v2.md | 2 +- .../beman_standard/readme/data/invalid/invalid-title-v3.md | 2 +- .../beman_standard/readme/data/invalid/invalid-title-v4.md | 2 +- .../lib/checks/beman_standard/readme/data/valid/README-v1.md | 2 +- .../lib/checks/beman_standard/readme/data/valid/README-v2.md | 2 +- .../lib/checks/beman_standard/readme/data/valid/README-v3.md | 2 +- .../lib/checks/beman_standard/readme/data/valid/README-v4.md | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md index d35e495f..5be8ed82 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md @@ -6,7 +6,7 @@ ![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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md index b73d201d..4aa668e9 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md @@ -6,7 +6,7 @@ ![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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md index 32c5ecaf..ffc08c34 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md @@ -6,7 +6,7 @@ ![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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md index efce73e1..bdef5791 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md +++ b/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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md index fdec922c..a4da50fc 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md index 64ca1ece..8d5e2bdd 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md index 62e492a4..7f91a7a3 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md index 45048301..e92b46f4 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md index aac812de..6ae059f0 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md index ef484ace..eea29e4b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md index fb9a816e..403859dd 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md index 1b8c4e04..56e5a729 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md index be64207e..dbfbacee 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.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) -**Purpose**: `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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md index 3fd85b14..c33c6037 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.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) -**Purpose**: `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). From 725f5691d03967db3d3a272cc4fe7a9fe6647d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 3 Jul 2025 23:30:21 +0300 Subject: [PATCH 249/371] [beman-tidy]: implement DIRECTORY.SOURCES --- .../beman-tidy/beman_tidy/.beman-standard.yml | 14 +---------- .../lib/checks/beman_standard/directory.py | 24 +++++++++++++------ .../lib/checks/beman_standard/readme.py | 2 -- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index 47519973..bfa38f50 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -111,30 +111,18 @@ CMAKE.AVOID_PASSTHROUGHS: # DIRECTORY DIRECTORY.INTERFACE_HEADERS: - type: REQUIREMENT - - directory_name: include - - regex: DIRECTORY.IMPLEMENTATION_HEADERS: - type: REQUIREMENT - - regex: DIRECTORY.SOURCES: - - type: REQUIREMENT - - directory_name: src - - regex: + - type: RECOMMENDATION # TODO: Why DIRECTORY.SOURCES is a RECOMMENDATION? 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 # FILE FILE.CPP_NAMES: diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index d533bb3a..546e1750 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -6,9 +6,19 @@ # [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. + Check if the directory tree is a Beman tree: ${prefix_path}/beman/${short_name}. + Examples for a repo named "exemplar": + - include/beman/exemplar + - src/beman/exemplar + - tests/beman/exemplar + - examples/beman/exemplar + - docs/beman/exemplar + - papers/beman/exemplar """ def __init__(self, repo_info, beman_standard_check_config, prefix_path): @@ -25,24 +35,24 @@ def __init__(self, repo_info, beman_standard_check_config, prefix_path): # TODO DIRECTORY.IMPLEMENTATION_HEADERS -# TODO DIRECTORY.SOURCES @register_beman_standard_check("DIRECTORY.SOURCES") class DirectorySourcesCheck(BemanTreeDirectoryCheck): """ Check if the sources directory is src/beman/. + + 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 check(self): - return self.pre_check() + return self.pre_check() # Check if the directory exists and is not empty. def fix(self): - """ - TODO: Implement the fix. - """ - pass + self.log( + f"Please move sources to src/beman/{self.repo_name}. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#directorysources for more information." + ) # TODO DIRECTORY.TESTS diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index fcbead60..38dca1e7 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -10,8 +10,6 @@ # 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") From 1a3fc969700b9c16c3181badce54faadea6ad4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Thu, 3 Jul 2025 23:40:35 +0300 Subject: [PATCH 250/371] [beman-tidy] Fix --fix-inplace mode --- tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py | 6 +++--- tools/beman-tidy/beman_tidy/lib/checks/system/git.py | 6 +++--- tools/beman-tidy/beman_tidy/lib/pipeline.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py index f3431ab6..a12b4a00 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py @@ -30,16 +30,16 @@ 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 not "INTERNAL." in self.name else None # set type - e.g. "REQUIREMENT" or "RECOMMENDATION" - self.type = beman_standard_check_config[self.name]["type"] + self.type = beman_standard_check_config[self.name]["type"] if not "INTERNAL." 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 not "INTERNAL." in self.name else "" assert self.full_text_body is not None # set log level - e.g. "ERROR" or "WARNING" diff --git a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py index ecc11456..9e1bfc92 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py @@ -8,11 +8,11 @@ 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 +25,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/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index a5d7d408..4905ee46 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -76,7 +76,7 @@ def run_check(check_class, log_enabled=args.verbose): def run_pipeline_helper(): # 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 From 9dca73f0c763c64d2a7cfdb9348cf02a685ee210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 4 Jul 2025 00:01:33 +0300 Subject: [PATCH 251/371] [beman-tidy] Clarify docs --- tools/beman-tidy/docs/dev-guide.md | 8 ++++---- .../lib/checks/beman_standard/readme/test_readme.py | 10 +++++----- tools/beman-tidy/tests/utils/file_testcase_runners.py | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index ea009412..036e4732 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -73,10 +73,10 @@ 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_invalid PASSED [ 50%] +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_invalid SKIPPED (NOT implemented) [100%] +tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_inplace SKIPPED (NOT implemented) [100%] =========================================================================================================== 5 passed, 1 skipped in 0.07s ============================================================================================================ ``` @@ -95,7 +95,7 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI `tests/lib/checks/beman_standard/readme/data/valid/`. * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in `tests/lib/checks/beman_standard/readme/data/invalid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "fix_invalid"` the data may use both `valid` and + * e.g., for `check_category = "readme"` and `test_case_name = "fix_inplace"` the data may use both `valid` and `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` (which are not tracked by git). * Default setup / mocks: @@ -105,7 +105,7 @@ tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_invalid SKI * Always add at least 3 test cases for each check. * `valid`: The test case for the valid case. * `invalid`: The test case for the invalid case. - * `fix_invalid`: The test case for the fix invalid case. If the fix is not (yet) implementable, add a + * `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. ## Changing dependencies diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 56e6f33e..5609eab1 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -7,7 +7,7 @@ from tests.utils.file_testcase_runners import ( file_testcases_run_valid, file_testcases_run_invalid, - file_testcases_run_fix_invalid, + file_testcases_run_fix_inplace, ) # Actual tested checks. @@ -59,7 +59,7 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): ) -def test__README_TITLE__fix_invalid(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. """ @@ -70,7 +70,7 @@ def test__README_TITLE__fix_invalid(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-title-v4.md"), ] - file_testcases_run_fix_invalid( + file_testcases_run_fix_inplace( invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config ) @@ -108,7 +108,7 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): @pytest.mark.skip(reason="NOT implemented") -def test__README_BADGES__fix_invalid(repo_info, beman_standard_check_config): +def test__README_BADGES__fix_inplace(repo_info, beman_standard_check_config): """ Test that the fix method corrects an invalid README.md badges. """ @@ -154,7 +154,7 @@ def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config) @pytest.mark.skip(reason="NOT implemented") -def test__README_LIBRARY_STATUS__fix_invalid(repo_info, beman_standard_check_config): +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. """ diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index 101f3418..91dcf77f 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -10,8 +10,8 @@ # - file_testcase_run # - file_testcase_run_ # - file_testcases_run_ -# - file_testcase_run_fix_invalid -# - file_testcases_run_fix_invalid +# - file_testcase_run_fix_inplace +# - file_testcases_run_fix_inplace def file_testcase_run( @@ -65,7 +65,7 @@ def file_testcase_run_invalid( ) -def file_testcase_run_fix_invalid( +def file_testcase_run_fix_inplace( invalid_file_path, check_class, repo_info, beman_standard_check_config ): """ @@ -152,7 +152,7 @@ def file_testcases_run_invalid( ) -def file_testcases_run_fix_invalid( +def file_testcases_run_fix_inplace( invalid_file_paths, check_class, repo_info, beman_standard_check_config ): """ @@ -169,6 +169,6 @@ def file_testcases_run_fix_invalid( beman_standard_check_config = "beman_tidy/.beman-standard.yml" """ for invalid_file_path in invalid_file_paths: - file_testcase_run_fix_invalid( + file_testcase_run_fix_inplace( invalid_file_path, check_class, repo_info, beman_standard_check_config ) From 8eaa3eac91d2c68b4ce53e6198ee845163061862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 4 Jul 2025 00:03:22 +0300 Subject: [PATCH 252/371] [beman-tidy] Reorder utils --- .../tests/utils/file_testcase_runners.py | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py index 91dcf77f..704644ba 100644 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ b/tools/beman-tidy/tests/utils/file_testcase_runners.py @@ -39,6 +39,24 @@ def file_testcase_run( ) +def file_testcases_run( + file_paths, check_class, repo_info, beman_standard_check_config, expected_result +): + """ + Run multiple testcases for a file-based check. + + Example: Similar to file_testcase_run(), but with multiple file_paths. + """ + for file_path in file_paths: + file_testcase_run( + file_path, + check_class, + repo_info, + beman_standard_check_config, + expected_result, + ) + + def file_testcase_run_valid( file_path, check_class, repo_info, beman_standard_check_config ): @@ -65,52 +83,6 @@ def file_testcase_run_invalid( ) -def file_testcase_run_fix_inplace( - invalid_file_path, check_class, repo_info, beman_standard_check_config -): - """ - Run a testcase for a file-based check, starting with a file that is invalid, - and then fixing it. - - Example: - invalid_file_path = "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md" - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - """ - check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(f"{invalid_file_path}.delete_me") - check_instance.write(invalid_file_path.read_text()) - - assert check_instance.pre_check() is True - assert check_instance.check() is False - - assert check_instance.fix() is True - - assert check_instance.pre_check() is True - assert check_instance.check() is True - - # Delete the temporary file - os.remove(f"{invalid_file_path}.delete_me") - - -def file_testcases_run( - file_paths, check_class, repo_info, beman_standard_check_config, expected_result -): - """ - Run multiple testcases for a file-based check. - - Example: Similar to file_testcase_run(), but with multiple file_paths. - """ - for file_path in file_paths: - file_testcase_run( - file_path, - check_class, - repo_info, - beman_standard_check_config, - expected_result, - ) - def file_testcases_run_valid( file_paths, check_class, repo_info, beman_standard_check_config @@ -151,6 +123,34 @@ def file_testcases_run_invalid( file_paths, check_class, repo_info, beman_standard_check_config, False ) +def file_testcase_run_fix_inplace( + invalid_file_path, check_class, repo_info, beman_standard_check_config +): + """ + Run a testcase for a file-based check, starting with a file that is invalid, + and then fixing it. + + Example: + invalid_file_path = "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md" + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + """ + check_instance = check_class(repo_info, beman_standard_check_config) + check_instance.path = Path(f"{invalid_file_path}.delete_me") + check_instance.write(invalid_file_path.read_text()) + + assert check_instance.pre_check() is True + assert check_instance.check() is False + + assert check_instance.fix() is True + + assert check_instance.pre_check() is True + assert check_instance.check() is True + + # Delete the temporary file + os.remove(f"{invalid_file_path}.delete_me") + def file_testcases_run_fix_inplace( invalid_file_paths, check_class, repo_info, beman_standard_check_config From d12fdabeab7a80cd75f84d51b6927461cfb32778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 4 Jul 2025 00:21:01 +0300 Subject: [PATCH 253/371] [beman-tidy] Simplify path runners, to be able to reuse them on files and directories --- .../beman_standard/readme/test_readme.py | 42 ++--- .../tests/utils/directory_testcase_runners.py | 4 - .../tests/utils/file_testcase_runners.py | 174 ------------------ tools/beman-tidy/tests/utils/path_runners.py | 72 ++++++++ 4 files changed, 90 insertions(+), 202 deletions(-) delete mode 100644 tools/beman-tidy/tests/utils/directory_testcase_runners.py delete mode 100644 tools/beman-tidy/tests/utils/file_testcase_runners.py create mode 100644 tools/beman-tidy/tests/utils/path_runners.py diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 5609eab1..af9f0035 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -4,10 +4,9 @@ import pytest from pathlib import Path -from tests.utils.file_testcase_runners import ( - file_testcases_run_valid, - file_testcases_run_invalid, - file_testcases_run_fix_inplace, +from tests.utils.path_runners import ( + run_check_for_each_path, + run_fix_inplace_for_each_file_path, ) # Actual tested checks. @@ -37,8 +36,8 @@ def test__README_TITLE__valid(repo_info, beman_standard_check_config): Path(f"{valid_prefix}/README-v4.md"), ] - file_testcases_run_valid( - valid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + run_check_for_each_path( + True, valid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config ) @@ -54,8 +53,8 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-title-v4.md"), ] - file_testcases_run_invalid( - invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + run_check_for_each_path( + False, invalid_readme_paths,ReadmeTitleCheck, repo_info, beman_standard_check_config ) @@ -70,8 +69,9 @@ def test__README_TITLE__fix_inplace(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-title-v4.md"), ] - file_testcases_run_fix_inplace( - invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + run_fix_inplace_for_each_file_path( + invalid_readme_paths, ReadmeTitleCheck, + repo_info, beman_standard_check_config ) @@ -86,8 +86,8 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config): Path(f"{valid_prefix}/README-v4.md"), ] - file_testcases_run_valid( - valid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config + run_check_for_each_path( + True, valid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config ) @@ -102,8 +102,8 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): Path(f"{invalid_prefix}/invalid-badge-v3.md"), ] - file_testcases_run_invalid( - invalid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config + run_check_for_each_path( + False, invalid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config ) @@ -126,11 +126,8 @@ def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): Path(f"{valid_prefix}/README-v4.md"), ] - file_testcases_run_valid( - valid_readme_paths, - ReadmeLibraryStatusCheck, - repo_info, - beman_standard_check_config, + run_check_for_each_path( + True, valid_readme_paths, ReadmeLibraryStatusCheck, repo_info, beman_standard_check_config ) @@ -145,11 +142,8 @@ def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config) Path(f"{invalid_prefix}/invalid-status-line-v3.md"), ] - file_testcases_run_invalid( - invalid_readme_paths, - ReadmeLibraryStatusCheck, - repo_info, - beman_standard_check_config, + run_check_for_each_path( + False, invalid_readme_paths, ReadmeLibraryStatusCheck, repo_info, beman_standard_check_config ) diff --git a/tools/beman-tidy/tests/utils/directory_testcase_runners.py b/tools/beman-tidy/tests/utils/directory_testcase_runners.py deleted file mode 100644 index f42e4740..00000000 --- a/tools/beman-tidy/tests/utils/directory_testcase_runners.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# TODO: Implement directory testcase runners diff --git a/tools/beman-tidy/tests/utils/file_testcase_runners.py b/tools/beman-tidy/tests/utils/file_testcase_runners.py deleted file mode 100644 index 704644ba..00000000 --- a/tools/beman-tidy/tests/utils/file_testcase_runners.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import os -from pathlib import Path - -# This file contains the testcase runners for the file-based checks. -# Some of the runners use a single file, while others use multiple files. -# The runners are named: -# - file_testcase_run -# - file_testcase_run_ -# - file_testcases_run_ -# - file_testcase_run_fix_inplace -# - file_testcases_run_fix_inplace - - -def file_testcase_run( - file_path, check_class, repo_info, beman_standard_check_config, expected_result -): - """ - Run a testcase for a file-based check. - - Example: - file_path = "tests/lib/checks/beman_standard/readme/data/valid/README-v1.md" - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - expected_result = True - """ - check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(file_path) - check_instance.log_level = True - - assert check_instance.pre_check() is True, ( - f"[{check_instance.__class__.__name__}] pre_check() failed for {file_path}" - ) - assert check_instance.check() is expected_result, ( - f"[{check_instance.__class__.__name__}] check() failed for {file_path}" - ) - - -def file_testcases_run( - file_paths, check_class, repo_info, beman_standard_check_config, expected_result -): - """ - Run multiple testcases for a file-based check. - - Example: Similar to file_testcase_run(), but with multiple file_paths. - """ - for file_path in file_paths: - file_testcase_run( - file_path, - check_class, - repo_info, - beman_standard_check_config, - expected_result, - ) - - -def file_testcase_run_valid( - file_path, check_class, repo_info, beman_standard_check_config -): - """ - Run a testcase for a file-based check. - - Example: Similar to file_testcase_run(), but with expected_result = True. - """ - file_testcase_run( - file_path, check_class, repo_info, beman_standard_check_config, True - ) - - -def file_testcase_run_invalid( - file_path, check_class, repo_info, beman_standard_check_config -): - """ - Run a testcase for a file-based check. - - Example: Similar to file_testcase_run(), but with expected_result = False. - """ - file_testcase_run( - file_path, check_class, repo_info, beman_standard_check_config, False - ) - - - -def file_testcases_run_valid( - file_paths, check_class, repo_info, beman_standard_check_config -): - """ - Run multiple testcases for a file-based check. - - Example: - file_paths = [ - "tests/lib/checks/beman_standard/readme/data/valid/README-v1.md", - "tests/lib/checks/beman_standard/readme/data/valid/README-v2.md", - ] - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - """ - file_testcases_run( - file_paths, check_class, repo_info, beman_standard_check_config, True - ) - - -def file_testcases_run_invalid( - file_paths, check_class, repo_info, beman_standard_check_config -): - """ - Run multiple testcases for a file-based check. - - Example: - file_paths = [ - "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md", - "tests/lib/checks/beman_standard/readme/data/invalid/README-v2.md", - ] - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - """ - file_testcases_run( - file_paths, check_class, repo_info, beman_standard_check_config, False - ) - -def file_testcase_run_fix_inplace( - invalid_file_path, check_class, repo_info, beman_standard_check_config -): - """ - Run a testcase for a file-based check, starting with a file that is invalid, - and then fixing it. - - Example: - invalid_file_path = "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md" - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - """ - check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(f"{invalid_file_path}.delete_me") - check_instance.write(invalid_file_path.read_text()) - - assert check_instance.pre_check() is True - assert check_instance.check() is False - - assert check_instance.fix() is True - - assert check_instance.pre_check() is True - assert check_instance.check() is True - - # Delete the temporary file - os.remove(f"{invalid_file_path}.delete_me") - - -def file_testcases_run_fix_inplace( - invalid_file_paths, check_class, repo_info, beman_standard_check_config -): - """ - Run multiple testcases for a file-based check, for each file starting with a file that is invalid, - and then fixing it. - - Example: - invalid_file_paths = [ - "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md", - "tests/lib/checks/beman_standard/readme/data/invalid/README-v2.md", - ] - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - """ - for invalid_file_path in invalid_file_paths: - file_testcase_run_fix_inplace( - invalid_file_path, check_class, repo_info, beman_standard_check_config - ) diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py new file mode 100644 index 00000000..9e42e5d2 --- /dev/null +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import os +from pathlib import Path + +def run_check_for_each_path( + expected_result, paths, check_class, repo_info, beman_standard_check_config +): + """ + Run path-based check (check_class) for each given path: evaluate check_class(paths[i]). + + Example: + expected_result = True / False + paths = [ + "tests/lib/checks/beman_standard/readme/data/valid/README-v1.md", + "tests/lib/checks/beman_standard/readme/data/valid/README-v2.md", + ] + check_class = ReadmeTitleCheck or DirectorySourcesCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "/path/to/.beman-standard.yml" + """ + for path in paths: + check_instance = check_class(repo_info, beman_standard_check_config) + 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}" + ) + assert check_instance.check() is expected_result, ( + f"[{check_instance.__class__.__name__}] check() failed for {path}" + ) + +def run_fix_inplace_for_each_file_path( + invalid_file_paths, check_class, repo_info, beman_standard_check_config +): + """ + Run multiple testcases for a file-based check, for each file starting with a file that is invalid, + and then fixing it. + + Example: + invalid_file_paths = [ + "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md", + "tests/lib/checks/beman_standard/readme/data/invalid/README-v2.md", + ] + check_class = ReadmeTitleCheck + repo_info = "beman.exemplar" + beman_standard_check_config = "beman_tidy/.beman-standard.yml" + """ + for invalid_path in invalid_file_paths: + check_instance = check_class(repo_info, beman_standard_check_config) + check_instance.path = Path(f"{invalid_path}.delete_me") + check_instance.write(invalid_path.read_text()) + + assert check_instance.pre_check() is True + assert check_instance.check() is False + + assert check_instance.fix() is True + + assert check_instance.pre_check() is True + assert check_instance.check() is True + + # Delete the temporary file + os.remove(f"{invalid_path}.delete_me") + + +def run_fix_inplace_for_each_directory_path( + invalid_directory_paths, check_class, repo_info, beman_standard_check_config +): + # TODO: We may not provide a fix_inplace method for directory-based checks. + pass \ No newline at end of file From 37869f21b41994e87e886e84c5410eb4767634ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 4 Jul 2025 00:25:17 +0300 Subject: [PATCH 254/371] [beman-tidy] Run precommit --- .../beman_standard/readme/test_readme.py | 39 +++++++++++++++---- tools/beman-tidy/tests/utils/path_runners.py | 6 ++- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index af9f0035..476a1804 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -37,7 +37,11 @@ def test__README_TITLE__valid(repo_info, beman_standard_check_config): ] run_check_for_each_path( - True, valid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config + True, + valid_readme_paths, + ReadmeTitleCheck, + repo_info, + beman_standard_check_config, ) @@ -54,7 +58,11 @@ def test__README_TITLE__invalid(repo_info, beman_standard_check_config): ] run_check_for_each_path( - False, invalid_readme_paths,ReadmeTitleCheck, repo_info, beman_standard_check_config + False, + invalid_readme_paths, + ReadmeTitleCheck, + repo_info, + beman_standard_check_config, ) @@ -70,8 +78,7 @@ def test__README_TITLE__fix_inplace(repo_info, beman_standard_check_config): ] run_fix_inplace_for_each_file_path( - invalid_readme_paths, ReadmeTitleCheck, - repo_info, beman_standard_check_config + invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config ) @@ -87,7 +94,11 @@ def test__README_BADGES__valid(repo_info, beman_standard_check_config): ] run_check_for_each_path( - True, valid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config + True, + valid_readme_paths, + ReadmeBadgesCheck, + repo_info, + beman_standard_check_config, ) @@ -103,7 +114,11 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): ] run_check_for_each_path( - False, invalid_readme_paths, ReadmeBadgesCheck, repo_info, beman_standard_check_config + False, + invalid_readme_paths, + ReadmeBadgesCheck, + repo_info, + beman_standard_check_config, ) @@ -127,7 +142,11 @@ def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): ] run_check_for_each_path( - True, valid_readme_paths, ReadmeLibraryStatusCheck, repo_info, beman_standard_check_config + True, + valid_readme_paths, + ReadmeLibraryStatusCheck, + repo_info, + beman_standard_check_config, ) @@ -143,7 +162,11 @@ def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config) ] run_check_for_each_path( - False, invalid_readme_paths, ReadmeLibraryStatusCheck, repo_info, beman_standard_check_config + False, + invalid_readme_paths, + ReadmeLibraryStatusCheck, + repo_info, + beman_standard_check_config, ) diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 9e42e5d2..e7b09ec0 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -4,6 +4,7 @@ import os from pathlib import Path + def run_check_for_each_path( expected_result, paths, check_class, repo_info, beman_standard_check_config ): @@ -30,7 +31,8 @@ def run_check_for_each_path( ) assert check_instance.check() is expected_result, ( f"[{check_instance.__class__.__name__}] check() failed for {path}" - ) + ) + def run_fix_inplace_for_each_file_path( invalid_file_paths, check_class, repo_info, beman_standard_check_config @@ -69,4 +71,4 @@ def run_fix_inplace_for_each_directory_path( invalid_directory_paths, check_class, repo_info, beman_standard_check_config ): # TODO: We may not provide a fix_inplace method for directory-based checks. - pass \ No newline at end of file + pass From 243e451b7b0dd545de68484d330c0f0f0d1af553 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Sat, 5 Jul 2025 23:37:19 -0400 Subject: [PATCH 255/371] Add toolchain for Clang with libc++ This inherits from the non-libc++ Clang toolchain file, but adds a -stdlib=libc++ parameter. --- cmake/llvm-libc++-toolchain.cmake | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 cmake/llvm-libc++-toolchain.cmake diff --git a/cmake/llvm-libc++-toolchain.cmake b/cmake/llvm-libc++-toolchain.cmake new file mode 100644 index 00000000..55fce9c4 --- /dev/null +++ b/cmake/llvm-libc++-toolchain.cmake @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: BSL-1.0 + +# This toolchain file is not meant to be used directly, +# but to be invoked by CMake preset and GitHub CI. +# +# This toolchain file configures for LLVM family of compiler. +# +# BEMAN_BUILDSYS_SANITIZER: +# This optional CMake parameter is not meant for public use and is subject to +# change. +# Possible values: +# - MaxSan: configures clang and clang++ to use all available non-conflicting +# sanitizers. +# - TSan: configures clang and clang++ to enable the use of thread sanitizer. + +include(${CMAKE_CURRENT_LIST_DIR}/llvm-toolchain.cmake) + +set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++" CACHE STRING "" FORCE) From 987540f757b01d74b9009b7bd7814db06569d0e3 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 6 Jul 2025 15:22:08 +0300 Subject: [PATCH 256/371] [beman-tidy] Add README.IMPLEMENTS check --- .../lib/checks/beman_standard/readme.py | 45 +++++++++++++++- .../data/invalid/invalid-implements-v1.md | 29 +++++++++++ .../data/invalid/invalid-implements-v2.md | 29 +++++++++++ .../data/invalid/invalid-implements-v3.md | 29 +++++++++++ .../beman_standard/readme/test_readme.py | 52 +++++++++++++++++++ 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index fcbead60..5611bdf6 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -75,8 +75,51 @@ def fix(self): # TODO README.PURPOSE -# TODO README.IMPLEMENTS +@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() + + bold_full_pattern = re.compile(r"^\*\*Implements\*\*:\s*\S.+") # Correct format with content + bold_empty_pattern = re.compile(r"^\*\*Implements\*\*:\s*$") # Correct format but empty + plain_pattern = re.compile(r"^Implements:\s*\S.+") # Unbolded, with content + plain_empty_pattern = re.compile(r"^Implements:\s*$") # Unbolded, but empty + + # Find and check the "Implements" line + for line in lines: + if bold_full_pattern.match(line): + return True # All good + + if bold_empty_pattern.match(line): + self.log( + f"The '**Implements**:' line in '{self.path}' is present but empty. Please add a one-line summary that indicates what the repository implements." + ) + return False + + if plain_pattern.match(line): + self.log( + f"Found 'Implements:' in '{self.path}', but it should be bolded as '**Implements**:'." + ) + return False + + if plain_empty_pattern.match(line): + self.log( + f"The 'Implements:' line in '{self.path}' is present but empty. It should be bolded as '**Implements**:' and is a one-line summary that indicates what the repository implements." + ) + return False + + # Nothing found + self.log( + f"Missing '**Implements**: ...' line in '{self.path}'. It should indicate what the repository implements after the badges. See BEMAN_STANDARD.md." + ) + return False + def fix(self): + # TODO + pass @register_beman_standard_check("README.LIBRARY_STATUS") class ReadmeLibraryStatusCheck(ReadmeBaseCheck): diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md new file mode 100644 index 00000000..6b8baed1 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md @@ -0,0 +1,29 @@ +# 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). + +**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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md new file mode 100644 index 00000000..9ff30e03 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md @@ -0,0 +1,29 @@ +# 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**: + +**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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md new file mode 100644 index 00000000..4a98e3c0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md @@ -0,0 +1,29 @@ +# 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: + +**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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 476a1804..04855182 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -13,6 +13,7 @@ from beman_tidy.lib.checks.beman_standard.readme import ( ReadmeTitleCheck, ReadmeBadgesCheck, + ReadmeImplementsCheck, ReadmeLibraryStatusCheck, ) @@ -130,6 +131,57 @@ def test__README_BADGES__fix_inplace(repo_info, beman_standard_check_config): pass +# TODO: README.PURPOSE + + +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"), + ] + + 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_invalid(repo_info, beman_standard_check_config): + """ + Test that the fix method corrects an invalid README.md "Implements" + """ + pass + + def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): """ Test that a valid README.md library status passes the check. From 59bee2047a07d7f3f5b72bc008ad271fed9535a2 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 6 Jul 2025 15:48:01 +0300 Subject: [PATCH 257/371] Refactor regex patterns for improved readability --- .../beman_tidy/lib/checks/beman_standard/readme.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 5611bdf6..b8e8eb64 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -83,15 +83,19 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): lines = self.read_lines_strip() - bold_full_pattern = re.compile(r"^\*\*Implements\*\*:\s*\S.+") # Correct format with content - bold_empty_pattern = re.compile(r"^\*\*Implements\*\*:\s*$") # Correct format but empty + bold_full_pattern = re.compile( + r"^\*\*Implements\*\*:\s*\S.+" + ) # Correct format with content + bold_empty_pattern = re.compile( + r"^\*\*Implements\*\*:\s*$" + ) # Correct format but empty plain_pattern = re.compile(r"^Implements:\s*\S.+") # Unbolded, with content plain_empty_pattern = re.compile(r"^Implements:\s*$") # Unbolded, but empty # Find and check the "Implements" line for line in lines: if bold_full_pattern.match(line): - return True # All good + return True # All good if bold_empty_pattern.match(line): self.log( @@ -121,6 +125,7 @@ def fix(self): # TODO pass + @register_beman_standard_check("README.LIBRARY_STATUS") class ReadmeLibraryStatusCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): From 0d1a5e80f9e292a8e6a6b35e6b563690bffcbf79 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 6 Jul 2025 15:48:01 +0300 Subject: [PATCH 258/371] Run linter --- .../lib/checks/beman_standard/readme.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 5611bdf6..6f701e5c 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -83,15 +83,19 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): lines = self.read_lines_strip() - bold_full_pattern = re.compile(r"^\*\*Implements\*\*:\s*\S.+") # Correct format with content - bold_empty_pattern = re.compile(r"^\*\*Implements\*\*:\s*$") # Correct format but empty - plain_pattern = re.compile(r"^Implements:\s*\S.+") # Unbolded, with content - plain_empty_pattern = re.compile(r"^Implements:\s*$") # Unbolded, but empty + bold_full_pattern = re.compile( + r"^\*\*Implements\*\*:\s*\S.+" + ) # Correct format with content + bold_empty_pattern = re.compile( + r"^\*\*Implements\*\*:\s*$" + ) # Correct format but empty + plain_pattern = re.compile(r"^Implements:\s*\S.+") # Unbolded, with content + plain_empty_pattern = re.compile(r"^Implements:\s*$") # Unbolded, but empty # Find and check the "Implements" line for line in lines: if bold_full_pattern.match(line): - return True # All good + return True # All good if bold_empty_pattern.match(line): self.log( @@ -121,6 +125,7 @@ def fix(self): # TODO pass + @register_beman_standard_check("README.LIBRARY_STATUS") class ReadmeLibraryStatusCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): From 1ed1ad5d8c02db1b4d1c93a60b9f87682be080f4 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 10:00:17 -0400 Subject: [PATCH 259/371] Implement allow_untracked_files This parameter allows beman submodules to be installed into a subdirectory without being the exclusive occupant of that subdirectory; it can contain other files which the beman submodule will clobber if they conflict with the submodule's repository, but it will not automatically remove those files. It is not enabled by default because it carries the risk that a file that was removed from the beman submodule's upstream will not be removed from the subdirectory. --- tools/beman-submodule/beman-submodule | 45 +++++++-- .../test/test_beman_submodule.py | 99 ++++++++++++++++--- 2 files changed, 122 insertions(+), 22 deletions(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 2558e559..281d20b2 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -5,6 +5,7 @@ import argparse import configparser import filecmp +import glob import os import shutil import subprocess @@ -27,10 +28,13 @@ def directory_compare(dir1: str | Path, dir2: str | Path, ignore): return True class BemanSubmodule: - def __init__(self, dirpath: str | Path, remote: str, commit_hash: str): + def __init__( + self, dirpath: str | Path, remote: str, commit_hash: str, + allow_untracked_files: bool): self.dirpath = Path(dirpath) self.remote = remote self.commit_hash = commit_hash + self.allow_untracked_files = allow_untracked_files def parse_beman_submodule_file(path): config = configparser.ConfigParser() @@ -45,10 +49,13 @@ def parse_beman_submodule_file(path): fail() if not 'commit_hash' in config['beman_submodule']: fail() + allow_untracked_files = config.getboolean( + 'beman_submodule', 'allow_untracked_files', fallback=False) return BemanSubmodule( Path(path).resolve().parent, config['beman_submodule']['remote'], - config['beman_submodule']['commit_hash']) + config['beman_submodule']['commit_hash'], + allow_untracked_files) def get_beman_submodule(path: str | Path): beman_submodule_filepath = Path(path) / '.beman_submodule' @@ -90,6 +97,12 @@ def clone_beman_submodule_into_tmpdir(beman_submodule, remote): capture_output=True, check=True) return tmpdir +def get_paths(beman_submodule): + tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, False) + paths = set(glob.glob('*', root_dir=Path(tmpdir.name), include_hidden=True)) + paths.remove('.git') + return paths + def beman_submodule_status(beman_submodule): tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, False) if directory_compare(tmpdir.name, beman_submodule.dirpath, ['.beman_submodule', '.git']): @@ -109,15 +122,26 @@ def beman_submodule_update(beman_submodule, remote): ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmp_path) - shutil.rmtree(beman_submodule.dirpath) + if beman_submodule.allow_untracked_files: + for path in get_paths(beman_submodule): + path2 = Path(beman_submodule.dirpath) / path + print("removing", path2) + if Path(path2).is_dir(): + shutil.rmtree(path2) + elif Path(path2).is_file(): + os.remove(path2) + else: + shutil.rmtree(beman_submodule.dirpath) submodule_path = tmp_path / '.beman_submodule' with open(submodule_path, 'w') as f: f.write('[beman_submodule]\n') f.write(f'remote={beman_submodule.remote}\n') f.write(f'commit_hash={sha_process.stdout.strip()}\n') + if beman_submodule.allow_untracked_files: + f.write(f'allow_untracked_files=True') shutil.rmtree(tmp_path / '.git') - shutil.copytree(tmp_path, beman_submodule.dirpath) + shutil.copytree(tmp_path, beman_submodule.dirpath, dirs_exist_ok=True) def update_command(remote, path): if not path: @@ -133,7 +157,7 @@ def update_command(remote, path): for beman_submodule in beman_submodules: beman_submodule_update(beman_submodule, remote) -def add_command(repository, path): +def add_command(repository, path, allow_untracked_files): tmpdir = tempfile.TemporaryDirectory() subprocess.run( ['git', 'clone', repository], capture_output=True, check=True, cwd=tmpdir.name) @@ -142,9 +166,9 @@ def add_command(repository, path): path = Path(repository_name) else: path = Path(path) - if path.exists(): + if not allow_untracked_files and path.exists(): raise Exception(f'{path} exists') - path.mkdir() + path.mkdir(exist_ok=allow_untracked_files) tmpdir_repo = Path(tmpdir.name) / repository_name sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, @@ -153,6 +177,8 @@ def add_command(repository, path): f.write('[beman_submodule]\n') f.write(f'remote={repository}\n') f.write(f'commit_hash={sha_process.stdout.strip()}\n') + if allow_untracked_files: + f.write(f'allow_untracked_files=True') shutil.rmtree(tmpdir_repo /'.git') shutil.copytree(tmpdir_repo, path, dirs_exist_ok=True) @@ -186,6 +212,9 @@ def get_parser(): parser_add.add_argument('repository', help='git repository to add') parser_add.add_argument( 'path', nargs='?', help='path where the repository will be added') + parser_add.add_argument( + '--allow-untracked-files', action='store_true', + help='the beman_submodule will not occupy the subdirectory exclusively') parser_status = subparsers.add_parser( 'status', help='show the status of beman_submodules') parser_status.add_argument('paths', nargs='*') @@ -201,7 +230,7 @@ def run_command(args): if args.command == 'update': update_command(args.remote, args.beman_submodule_path) elif args.command == 'add': - add_command(args.repository, args.path) + add_command(args.repository, args.path, args.allow_untracked_files) elif args.command == 'status': status_command(args.paths) else: diff --git a/tools/beman-submodule/test/test_beman_submodule.py b/tools/beman-submodule/test/test_beman_submodule.py index 746e08d1..fa7513f4 100644 --- a/tools/beman-submodule/test/test_beman_submodule.py +++ b/tools/beman-submodule/test/test_beman_submodule.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import glob import os import pytest import shutil @@ -35,6 +36,32 @@ def make_commit(a_txt_contents): make_commit('a') return tmpdir +def create_test_git_repository2(): + tmpdir = tempfile.TemporaryDirectory() + tmp_path = Path(tmpdir.name) + + subprocess.run(['git', 'init'], check=True, cwd=tmpdir.name, capture_output=True) + with open(tmp_path / 'a.txt', 'w') as f: + f.write('a') + subprocess.run( + ['git', 'add', 'a.txt'], check=True, cwd=tmpdir.name, capture_output=True) + subprocess.run( + ['git', '-c', 'user.name=test', '-c', 'user.email=test@example.com', 'commit', + '--author="test "', '-m', 'test'], + check=True, cwd=tmpdir.name, capture_output=True) + os.remove(tmp_path / 'a.txt') + subprocess.run( + ['git', 'rm', 'a.txt'], check=True, cwd=tmpdir.name, capture_output=True) + with open(tmp_path / 'b.txt', 'w') as f: + f.write('b') + subprocess.run( + ['git', 'add', 'b.txt'], check=True, cwd=tmpdir.name, capture_output=True) + subprocess.run( + ['git', '-c', 'user.name=test', '-c', 'user.email=test@example.com', 'commit', + '--author="test "', '-m', 'test'], + check=True, cwd=tmpdir.name, capture_output=True) + return tmpdir + def test_directory_compare(): def create_dir_structure(dir_path: Path): bar_path = dir_path / 'bar' @@ -122,7 +149,7 @@ def test_get_beman_submodule(): tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'foo', False) assert beman_submodule.get_beman_submodule('foo') os.remove('foo/.beman_submodule') assert not beman_submodule.get_beman_submodule('foo') @@ -133,8 +160,8 @@ def test_find_beman_submodules_in(): tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') + beman_submodule.add_command(tmpdir.name, 'foo', False) + beman_submodule.add_command(tmpdir.name, 'bar', False) beman_submodules = beman_submodule.find_beman_submodules_in(tmpdir2.name) sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, @@ -166,7 +193,7 @@ def test_clone_beman_submodule_into_tmpdir(): ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, cwd=tmpdir.name) sha = sha_process.stdout.strip() - beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'foo', False) module = beman_submodule.get_beman_submodule(Path(tmpdir2.name) / 'foo') module.commit_hash = sha tmpdir3 = beman_submodule.clone_beman_submodule_into_tmpdir(module, False) @@ -179,12 +206,22 @@ def test_clone_beman_submodule_into_tmpdir(): assert beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git']) os.chdir(original_cwd) +def test_get_paths(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = Path.cwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo', False) + module = beman_submodule.get_beman_submodule(Path(tmpdir2.name) / 'foo') + assert beman_submodule.get_paths(module) == set(['a.txt']) + os.chdir(original_cwd) + def test_beman_submodule_status(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'foo', False) sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) @@ -217,8 +254,8 @@ def test_update_command_no_paths(): subprocess.run( ['git', 'reset', '--hard', parent_parent_sha], capture_output=True, check=True, cwd=tmpdir.name) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') + beman_submodule.add_command(tmpdir.name, 'foo', False) + beman_submodule.add_command(tmpdir.name, 'bar', False) subprocess.run( ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, cwd=tmpdir.name) @@ -274,8 +311,8 @@ def test_update_command_with_path(): cwd=tmpdir.name) tmpdir_parent_parent_copy = tempfile.TemporaryDirectory() shutil.copytree(tmpdir.name, tmpdir_parent_parent_copy.name, dirs_exist_ok=True) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') + beman_submodule.add_command(tmpdir.name, 'foo', False) + beman_submodule.add_command(tmpdir.name, 'bar', False) subprocess.run( ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, cwd=tmpdir.name) @@ -309,12 +346,35 @@ def test_update_command_with_path(): tmpdir_parent_parent_copy.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) os.chdir(original_cwd) +def test_update_command_untracked_files(): + tmpdir = create_test_git_repository2() + tmpdir2 = create_test_git_repository() + original_cwd = Path.cwd(); + os.chdir(tmpdir2.name) + orig_sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + orig_sha = orig_sha_process.stdout.strip() + parent_sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + parent_sha = parent_sha_process.stdout.strip() + os.makedirs(Path(tmpdir2.name) / 'foo') + (Path(tmpdir2.name) / 'foo' / 'c.txt').touch() + with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'w') as f: + f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\nallow_untracked_files=True') + beman_submodule.update_command(False, 'foo') + assert set(['./foo/a.txt', './foo/c.txt']) == set(glob.glob('./foo/*.txt')) + beman_submodule.update_command(True, 'foo') + assert set(['./foo/b.txt', './foo/c.txt']) == set(glob.glob('./foo/*.txt')) + os.chdir(original_cwd) + def test_add_command(): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') + beman_submodule.add_command(tmpdir.name, 'foo', False) sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) @@ -325,13 +385,24 @@ def test_add_command(): assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n' os.chdir(original_cwd) +def test_add_command_untracked_files(): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = Path.cwd() + os.chdir(tmpdir2.name) + os.makedirs(Path(tmpdir2.name) / 'foo') + (Path(tmpdir2.name) / 'foo' / 'c.txt').touch() + beman_submodule.add_command(tmpdir.name, 'foo', True) + assert set(['./foo/a.txt', './foo/c.txt']) == set(glob.glob('./foo/*.txt')) + os.chdir(original_cwd) + def test_status_command_no_paths(capsys): tmpdir = create_test_git_repository() tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') + beman_submodule.add_command(tmpdir.name, 'foo', False) + beman_submodule.add_command(tmpdir.name, 'bar', False) sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) @@ -347,8 +418,8 @@ def test_status_command_with_path(capsys): tmpdir2 = create_test_git_repository() original_cwd = Path.cwd() os.chdir(tmpdir2.name) - beman_submodule.add_command(tmpdir.name, 'foo') - beman_submodule.add_command(tmpdir.name, 'bar') + beman_submodule.add_command(tmpdir.name, 'foo', False) + beman_submodule.add_command(tmpdir.name, 'bar', False) sha_process = subprocess.run( ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, cwd=tmpdir.name) From feed9cfd6ef8e3e3ce5e3b86a06c37c35c8597a5 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 10:24:09 -0400 Subject: [PATCH 260/371] [beman-submodule] Fix status command with untracked files 1ed1ad5d8c02db1b4d1c93a60b9f87682be080f4 implemented the allow_untracked_files parameter, but beman submodules with untracked files would still appear as "modified" in the status command. This commit addresses the bug and adds reproducing unit tests. --- tools/beman-submodule/beman-submodule | 21 ++++-- .../test/test_beman_submodule.py | 75 +++++++++++++++---- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 281d20b2..394a10ec 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -14,16 +14,19 @@ import tempfile from pathlib import Path -def directory_compare(dir1: str | Path, dir2: str | Path, ignore): - dir1, dir2 = Path(dir1), Path(dir2) +def directory_compare( + reference: str | Path, actual: str | Path, ignore, allow_untracked_files: bool): + reference, actual = Path(reference), Path(actual) - compared = filecmp.dircmp(dir1, dir2, ignore=ignore) - if compared.left_only or compared.right_only or compared.diff_files: + compared = filecmp.dircmp(reference, actual, ignore=ignore) + if (compared.left_only + or (compared.right_only and not allow_untracked_files) + or compared.diff_files): return False for common_dir in compared.common_dirs: - path1 = dir1 / common_dir - path2 = dir2 / common_dir - if not directory_compare(path1, path2, ignore): + path1 = reference / common_dir + path2 = actual / common_dir + if not directory_compare(path1, path2, ignore, allow_untracked_files): return False return True @@ -105,7 +108,9 @@ def get_paths(beman_submodule): def beman_submodule_status(beman_submodule): tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, False) - if directory_compare(tmpdir.name, beman_submodule.dirpath, ['.beman_submodule', '.git']): + if directory_compare( + tmpdir.name, beman_submodule.dirpath, ['.beman_submodule', '.git'], + beman_submodule.allow_untracked_files): status_character=' ' else: status_character='+' diff --git a/tools/beman-submodule/test/test_beman_submodule.py b/tools/beman-submodule/test/test_beman_submodule.py index fa7513f4..600fc070 100644 --- a/tools/beman-submodule/test/test_beman_submodule.py +++ b/tools/beman-submodule/test/test_beman_submodule.py @@ -80,13 +80,40 @@ def create_dir_structure(dir_path: Path): create_dir_structure(path_a) create_dir_structure(path_b) - assert beman_submodule.directory_compare(dir_a, dir_b, []) + assert beman_submodule.directory_compare(dir_a, dir_b, [], False) with open(path_a / 'bar' / 'quux.txt', 'w') as f: f.write('quux') - assert not beman_submodule.directory_compare(path_a, path_b, []) - assert beman_submodule.directory_compare(path_a, path_b, ['quux.txt']) + assert not beman_submodule.directory_compare(path_a, path_b, [], False) + assert beman_submodule.directory_compare(path_a, path_b, ['quux.txt'], False) + +def test_directory_compare_untracked_files(): + def create_dir_structure(dir_path: Path): + bar_path = dir_path / 'bar' + os.makedirs(bar_path) + + with open(dir_path / 'foo.txt', 'w') as f: + f.write('foo') + with open(bar_path / 'baz.txt', 'w') as f: + f.write('baz') + + with tempfile.TemporaryDirectory() as reference, \ + tempfile.TemporaryDirectory() as actual: + path_a = Path(reference) + path_b = Path(actual) + + create_dir_structure(path_a) + create_dir_structure(path_b) + (path_b / 'c.txt').touch() + + assert beman_submodule.directory_compare(reference, actual, [], True) + + with open(path_a / 'bar' / 'quux.txt', 'w') as f: + f.write('quux') + + assert not beman_submodule.directory_compare(path_a, path_b, [], True) + assert beman_submodule.directory_compare(path_a, path_b, ['quux.txt'], True) def test_parse_beman_submodule_file(): def valid_file(): @@ -197,13 +224,14 @@ def test_clone_beman_submodule_into_tmpdir(): module = beman_submodule.get_beman_submodule(Path(tmpdir2.name) / 'foo') module.commit_hash = sha tmpdir3 = beman_submodule.clone_beman_submodule_into_tmpdir(module, False) - assert not beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git']) + assert not beman_submodule.directory_compare( + tmpdir.name, tmpdir3.name, ['.git'], False) tmpdir4 = beman_submodule.clone_beman_submodule_into_tmpdir(module, True) - assert beman_submodule.directory_compare(tmpdir.name, tmpdir4.name, ['.git']) + assert beman_submodule.directory_compare(tmpdir.name, tmpdir4.name, ['.git'], False) subprocess.run( ['git', 'reset', '--hard', sha], capture_output=True, check=True, cwd=tmpdir.name) - assert beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git']) + assert beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git'], False) os.chdir(original_cwd) def test_get_paths(): @@ -272,9 +300,9 @@ def test_update_command_no_paths(): ['git', 'reset', '--hard', parent_sha], capture_output=True, check=True, cwd=tmpdir.name) assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule'], False) assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule'], False) subprocess.run( ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, cwd=tmpdir.name) @@ -284,9 +312,9 @@ def test_update_command_no_paths(): with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'r') as f: assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={orig_sha}\n' assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule'], False) assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule'], False) os.chdir(original_cwd) def test_update_command_with_path(): @@ -329,9 +357,10 @@ def test_update_command_with_path(): ['git', 'reset', '--hard', parent_sha], capture_output=True, check=True, cwd=tmpdir.name) assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule'], False) assert beman_submodule.directory_compare( - tmpdir_parent_parent_copy.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + tmpdir_parent_parent_copy.name, + Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule'], False) subprocess.run( ['git', 'reset', '--hard', orig_sha], capture_output=True, check=True, cwd=tmpdir.name) @@ -341,9 +370,10 @@ def test_update_command_with_path(): with open(Path(tmpdir2.name) / 'bar' / '.beman_submodule', 'r') as f: assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={parent_sha}\n' assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule'], False) assert beman_submodule.directory_compare( - tmpdir_parent_parent_copy.name, Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule']) + tmpdir_parent_parent_copy.name, + Path(tmpdir2.name) / 'bar', ['.git', '.beman_submodule'], False) os.chdir(original_cwd) def test_update_command_untracked_files(): @@ -380,7 +410,7 @@ def test_add_command(): cwd=tmpdir.name) sha = sha_process.stdout.strip() assert beman_submodule.directory_compare( - tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule']) + tmpdir.name, Path(tmpdir2.name) / 'foo', ['.git', '.beman_submodule'], False) with open(Path(tmpdir2.name) / 'foo' / '.beman_submodule', 'r') as f: assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n' os.chdir(original_cwd) @@ -430,6 +460,21 @@ def test_status_command_with_path(capsys): assert capsys.readouterr().out == '+ ' + sha + ' bar\n' os.chdir(original_cwd) +def test_status_command_untracked_files(capsys): + tmpdir = create_test_git_repository() + tmpdir2 = create_test_git_repository() + original_cwd = Path.cwd() + os.chdir(tmpdir2.name) + beman_submodule.add_command(tmpdir.name, 'foo', True) + sha_process = subprocess.run( + ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True, + cwd=tmpdir.name) + (Path(tmpdir2.name) / 'foo' / 'c.txt').touch() + beman_submodule.status_command(['foo']) + sha = sha_process.stdout.strip() + assert capsys.readouterr().out == ' ' + sha + ' foo\n' + os.chdir(original_cwd) + def test_check_for_git(): tmpdir = tempfile.TemporaryDirectory() assert not beman_submodule.check_for_git(tmpdir.name) From f33b449d636415c60ddcaec8aaf406ce73757f14 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 7 Jul 2025 17:56:57 +0300 Subject: [PATCH 261/371] [beman-tidy] Refactor README.IMPLEMENTS check for improved validation and update test cases --- .../lib/checks/beman_standard/readme.py | 49 +++++++------------ .../data/invalid/invalid-implements-v1.md | 2 +- .../data/invalid/invalid-implements-v2.md | 2 +- .../data/invalid/invalid-implements-v3.md | 2 +- .../beman_standard/readme/test_readme.py | 2 +- 5 files changed, 22 insertions(+), 35 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 6f701e5c..160827ab 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -83,41 +83,28 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): lines = self.read_lines_strip() - bold_full_pattern = re.compile( - r"^\*\*Implements\*\*:\s*\S.+" - ) # Correct format with content - bold_empty_pattern = re.compile( - r"^\*\*Implements\*\*:\s*$" - ) # Correct format but empty - plain_pattern = re.compile(r"^Implements:\s*\S.+") # Unbolded, with content - plain_empty_pattern = re.compile(r"^Implements:\s*$") # Unbolded, but empty - - # Find and check the "Implements" line + regex = r"^\*\*Implements\*\*:\s+.*\bP\d{4}R\d+\b.*wg21\.link/\S+" + + # Find and check the "Implements:" line for line in lines: - if bold_full_pattern.match(line): - return True # All good - - if bold_empty_pattern.match(line): - self.log( - f"The '**Implements**:' line in '{self.path}' is present but empty. Please add a one-line summary that indicates what the repository implements." - ) - return False - - if plain_pattern.match(line): - self.log( - f"Found 'Implements:' in '{self.path}', but it should be bolded as '**Implements**:'." - ) - return False - - if plain_empty_pattern.match(line): - self.log( - f"The 'Implements:' line in '{self.path}' is present but empty. It should be bolded as '**Implements**:' and is a one-line summary that indicates what the repository implements." - ) - return False + if "Implements" in line: + if re.match(regex, line): + return True + else: + self.log( + "\n\tThe \"Implements:\" line is invalid.\n" + "\tIt should indicate which papers the repository implements with proper paper references and wg21.link URLs.\n" + "\tUse the following style:\n" + "\t**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3).\n" + ) + return False # Nothing found self.log( - f"Missing '**Implements**: ...' line in '{self.path}'. It should indicate what the repository implements after the badges. See BEMAN_STANDARD.md." + f"\n\tMissing \"Implements:\" line in '{self.path}'.\n" + "\tIt should indicate which papers the repository implements with proper paper references and wg21.link URLs.\n" + "\tUse the following style:\n" + "\t**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3).\n" ) return False diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md index 6b8baed1..80cc4cea 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v1.md @@ -10,7 +10,7 @@ `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**: `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) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md index 9ff30e03..effdfcf7 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v2.md @@ -10,7 +10,7 @@ `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**: +**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) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md index 4a98e3c0..d403ac9c 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v3.md @@ -10,7 +10,7 @@ `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: +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) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 04855182..45734198 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -175,7 +175,7 @@ def test__README_IMPLEMENTS__invalid(repo_info, beman_standard_check_config): @pytest.mark.skip(reason="NOT implemented") -def test__README_IMPLEMENTS__fix_invalid(repo_info, beman_standard_check_config): +def test__README_IMPLEMENTS__fix_inplace(repo_info, beman_standard_check_config): """ Test that the fix method corrects an invalid README.md "Implements" """ From 3c97b3819415ced126232f3ebc948c64bd48d3a0 Mon Sep 17 00:00:00 2001 From: vickgoodman Date: Mon, 7 Jul 2025 18:01:44 +0300 Subject: [PATCH 262/371] Run linter Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 160827ab..8eb3453e 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -92,7 +92,7 @@ def check(self): return True else: self.log( - "\n\tThe \"Implements:\" line is invalid.\n" + '\n\tThe "Implements:" line is invalid.\n' "\tIt should indicate which papers the repository implements with proper paper references and wg21.link URLs.\n" "\tUse the following style:\n" "\t**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3).\n" From edf002a83cd873010b0789cfb6cbff53061f186f Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 11:01:19 -0400 Subject: [PATCH 263/371] [beman-submodule] Fix missing newline at end of file with allow_untracked_files --- tools/beman-submodule/beman-submodule | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 394a10ec..9e851d3b 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -183,7 +183,7 @@ def add_command(repository, path, allow_untracked_files): f.write(f'remote={repository}\n') f.write(f'commit_hash={sha_process.stdout.strip()}\n') if allow_untracked_files: - f.write(f'allow_untracked_files=True') + f.write(f'allow_untracked_files=True\n') shutil.rmtree(tmpdir_repo /'.git') shutil.copytree(tmpdir_repo, path, dirs_exist_ok=True) From 1f70e02786ba9eaa1d7d500ff1bb6095bb1d73ec Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 19:09:47 -0400 Subject: [PATCH 264/371] [beman-submodule] Fix debug print in update function This debug print was not removed before the new functionality was merged. --- tools/beman-submodule/beman-submodule | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 9e851d3b..97c44610 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -130,7 +130,6 @@ def beman_submodule_update(beman_submodule, remote): if beman_submodule.allow_untracked_files: for path in get_paths(beman_submodule): path2 = Path(beman_submodule.dirpath) / path - print("removing", path2) if Path(path2).is_dir(): shutil.rmtree(path2) elif Path(path2).is_file(): From f31c3491b1931d7025da4ce839cb87bb172bea8e Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 19:19:58 -0400 Subject: [PATCH 265/371] [beman-submodule] Fix another missing newline edf002a83cd873010b0789cfb6cbff53061f186f missed a spot. --- tools/beman-submodule/beman-submodule | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-submodule/beman-submodule b/tools/beman-submodule/beman-submodule index 97c44610..66cb96e1 100755 --- a/tools/beman-submodule/beman-submodule +++ b/tools/beman-submodule/beman-submodule @@ -143,7 +143,7 @@ def beman_submodule_update(beman_submodule, remote): f.write(f'remote={beman_submodule.remote}\n') f.write(f'commit_hash={sha_process.stdout.strip()}\n') if beman_submodule.allow_untracked_files: - f.write(f'allow_untracked_files=True') + f.write(f'allow_untracked_files=True\n') shutil.rmtree(tmp_path / '.git') shutil.copytree(tmp_path, beman_submodule.dirpath, dirs_exist_ok=True) From 69cb603548351241177a727e5e23d0be4033e5e4 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 21:15:27 -0400 Subject: [PATCH 266/371] use-fetch-content.cmake: Support lockfiles with zero dependencies Previously, configuration would error out upon encountering this lockfile: { "dependencies": [] } --- cmake/use-fetch-content.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/use-fetch-content.cmake b/cmake/use-fetch-content.cmake index 82c5db29..8e5cbacb 100644 --- a/cmake/use-fetch-content.cmake +++ b/cmake/use-fetch-content.cmake @@ -59,6 +59,10 @@ function(BemanExemplar_provideDependency method package_name) message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}") endif() + if(BemanExemplar_numDependencies EQUAL 0) + return() + endif() + # Loop over each dependency object math(EXPR BemanExemplar_maxIndex "${BemanExemplar_numDependencies} - 1") foreach(BemanExemplar_index RANGE "${BemanExemplar_maxIndex}") From 296ef479c15b94e38476b4bd6d11e06b5569babb Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 21:22:53 -0400 Subject: [PATCH 267/371] Indentation fix and add CMake linter to pre-commit --- .pre-commit-config.yaml | 7 +++++++ cmake/use-fetch-content.cmake | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6df26854..3c22d577 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,13 @@ repos: hooks: - id: codespell + # CMake linting and formatting + - repo: https://github.com/BlankSpruce/gersemi + rev: 0.15.1 + hooks: + - id: gersemi + name: CMake linting + # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ diff --git a/cmake/use-fetch-content.cmake b/cmake/use-fetch-content.cmake index 8e5cbacb..07c1a15d 100644 --- a/cmake/use-fetch-content.cmake +++ b/cmake/use-fetch-content.cmake @@ -60,7 +60,7 @@ function(BemanExemplar_provideDependency method package_name) endif() if(BemanExemplar_numDependencies EQUAL 0) - return() + return() endif() # Loop over each dependency object From ef60c1fbf6bad0c73577181669d161e26e434e23 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Mon, 7 Jul 2025 22:56:31 -0400 Subject: [PATCH 268/371] Fix libc++ toolchain file Previously, when a user specified -DCMAKE_CXX_FLAGS on the command line, it would blow away the -stdlib=libc++ parameter. --- cmake/llvm-libc++-toolchain.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/llvm-libc++-toolchain.cmake b/cmake/llvm-libc++-toolchain.cmake index 55fce9c4..027e467f 100644 --- a/cmake/llvm-libc++-toolchain.cmake +++ b/cmake/llvm-libc++-toolchain.cmake @@ -15,4 +15,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/llvm-toolchain.cmake) -set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++" CACHE STRING "" FORCE) +if(NOT CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+") + string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++") +endif() From 78de7eb4ff54bd12c9abb790107edc86bcda07d8 Mon Sep 17 00:00:00 2001 From: Eddie Nolan Date: Mon, 7 Jul 2025 22:58:17 -0400 Subject: [PATCH 269/371] Update cmake/llvm-libc++-toolchain.cmake Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- cmake/llvm-libc++-toolchain.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/llvm-libc++-toolchain.cmake b/cmake/llvm-libc++-toolchain.cmake index 027e467f..76264c69 100644 --- a/cmake/llvm-libc++-toolchain.cmake +++ b/cmake/llvm-libc++-toolchain.cmake @@ -16,5 +16,5 @@ include(${CMAKE_CURRENT_LIST_DIR}/llvm-toolchain.cmake) if(NOT CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+") - string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++") + string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++") endif() From 39cbd72468bfb43bcd11d2e5466d487f3fe7aaf9 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 8 Jul 2025 13:13:34 +0300 Subject: [PATCH 270/371] [beman-tidy] Refactor README.IMPLEMENTS check to improve validation and logging for "Implements:" line --- .../lib/checks/beman_standard/readme.py | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 8eb3453e..4fa4e798 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -72,9 +72,6 @@ def fix(self): pass -# TODO README.PURPOSE - - @register_beman_standard_check("README.IMPLEMENTS") class ReadmeImplementsCheck(ReadmeBaseCheck): def __init__(self, repo_info, beman_standard_check_config): @@ -83,34 +80,28 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): lines = self.read_lines_strip() + # Match the pattern to start with "Implements:" and then have a paper reference and a wg21.link URL. + # Examples of valid lines: + # **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) regex = r"^\*\*Implements\*\*:\s+.*\bP\d{4}R\d+\b.*wg21\.link/\S+" # Find and check the "Implements:" line for line in lines: - if "Implements" in line: - if re.match(regex, line): - return True - else: - self.log( - '\n\tThe "Implements:" line is invalid.\n' - "\tIt should indicate which papers the repository implements with proper paper references and wg21.link URLs.\n" - "\tUse the following style:\n" - "\t**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3).\n" - ) - return False + if re.match(regex, line): + return True # Nothing found self.log( - f"\n\tMissing \"Implements:\" line in '{self.path}'.\n" - "\tIt should indicate which papers the repository implements with proper paper references and wg21.link URLs.\n" - "\tUse the following style:\n" - "\t**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3).\n" + f"Invalid '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): - # TODO - pass + 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 False @register_beman_standard_check("README.LIBRARY_STATUS") From 82214005863ae91e13b928d65a1757abf3834351 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 8 Jul 2025 13:38:19 +0300 Subject: [PATCH 271/371] [beman-tidy] Removed #TODO: README.PURPOSE line from test_readme.py --- .../tests/lib/checks/beman_standard/readme/test_readme.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 45734198..8b7ed88f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -131,9 +131,6 @@ def test__README_BADGES__fix_inplace(repo_info, beman_standard_check_config): pass -# TODO: README.PURPOSE - - def test__README_IMPLEMENTS__valid(repo_info, beman_standard_check_config): """ Test that a valid README.md "Implements" passes the check From 4dff5af64d514f3d643b58e2cf9cb4f0c28702cb Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 8 Jul 2025 14:46:01 +0300 Subject: [PATCH 272/371] [beman-tidy] Added multi-line check for README.IMPLEMENTS --- .../lib/checks/beman_standard/readme.py | 16 +++++++--- .../data/invalid/invalid-implements-v4.md | 31 +++++++++++++++++++ .../beman_standard/readme/test_readme.py | 1 + 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 4fa4e798..d6b21666 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -82,18 +82,24 @@ def check(self): # Match the pattern to start with "Implements:" and then have a paper reference and a wg21.link URL. # Examples of valid lines: - # **Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). + # **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+" - # Find and check the "Implements:" line + # Count how many lines match the regex + implement_lines = 0 for line in lines: if re.match(regex, line): - return True + implement_lines += 1 - # Nothing found + # If there is exactly one "Implements:" line, it is valid + if implement_lines == 1: + return True + + # Invalid/missing/multiple "Implements:" lines self.log( - f"Invalid 'Implements' line in '{self.path}'. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmeimplements for more information." + f"Invalid/missing/multiple 'Implements:' lines in '{self.path}'. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmeimplements for more information." ) return False diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md new file mode 100644 index 00000000..93ada4cd --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-implements-v4.md @@ -0,0 +1,31 @@ +# 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 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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 8b7ed88f..87df91ee 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -160,6 +160,7 @@ def test__README_IMPLEMENTS__invalid(repo_info, beman_standard_check_config): 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( From 209208e14dd854e1fab17d7c58c4bc210c051c81 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 8 Jul 2025 16:09:14 +0300 Subject: [PATCH 273/371] [beman-tidy] Update log message for README.IMPLEMENTS check --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index d6b21666..92a85751 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -97,9 +97,9 @@ def check(self): if implement_lines == 1: return True - # Invalid/missing/multiple "Implements:" lines + # Invalid/missing/duplicate "Implements:" line self.log( - f"Invalid/missing/multiple 'Implements:' lines in '{self.path}'. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmeimplements for more information." + 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 From 8deaf109c5312795613f1263b8d7ecf2ea3eb1b6 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 9 Jul 2025 15:40:45 +0300 Subject: [PATCH 274/371] [beman-tidy] Enhance path check handling for directory and file checks --- tools/beman-tidy/tests/utils/path_runners.py | 21 +++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index e7b09ec0..74ab9b6f 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -22,13 +22,24 @@ def run_check_for_each_path( beman_standard_check_config = "/path/to/.beman-standard.yml" """ for path in paths: - check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(path) + 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) + else: + # For file checks, set the path directly on the check instance + check_instance = check_class(repo_info, beman_standard_check_config) + 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 not os.path.isdir(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}" ) From f5938f0b3a72714eddde05792b0862a0d24c12cd Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 9 Jul 2025 15:42:22 +0300 Subject: [PATCH 275/371] [beman-tidy] Added tests for TOPLEVEL.CMAKE --- .../beman_standard/toplevel/__init__.py | 0 .../beman_standard/toplevel/conftest.py | 16 + .../data/invalid/repo_without_cmake/LICENSE | 234 ++++++++++ .../data/invalid/repo_without_cmake/README.md | 399 ++++++++++++++++++ .../data/valid/complete_repo/CMakeLists.txt | 43 ++ .../toplevel/data/valid/complete_repo/LICENSE | 234 ++++++++++ .../data/valid/complete_repo/README.md | 399 ++++++++++++++++++ .../data/valid/repo_with_cmake/CMakeLists.txt | 43 ++ .../beman_standard/toplevel/test_toplevel.py | 60 +++ 9 files changed, 1428 insertions(+) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/conftest.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/conftest.py new file mode 100644 index 00000000..515dc2bd --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE new file mode 100644 index 00000000..0873f35a --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE @@ -0,0 +1,234 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + 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. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md new file mode 100644 index 00000000..1e714a1f --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md @@ -0,0 +1,399 @@ +# 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/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. + +**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) + +## Usage + +`std::identity` is a function object type whose `operator()` returns its argument unchanged. +`std::identity` serves as the default projection in constrained algorithms. +Its direct usage is usually not needed. + +### Usage: default projection in constrained algorithms + +The following code snippet illustrates how we can achieve a default projection using `beman::exemplar::identity`: + +```cpp +#include + +namespace exe = beman::exemplar; + +// Class with a pair of values. +struct Pair +{ + int n; + std::string s; + + // Output the pair in the form {n, s}. + // Used by the range-printer if no custom projection is provided (default: identity projection). + friend std::ostream &operator<<(std::ostream &os, const Pair &p) + { + return os << "Pair" << '{' << p.n << ", " << p.s << '}'; + } +}; + +// A range-printer that can print projected (modified) elements of a range. +// All the elements of the range are printed in the form {element1, element2, ...}. +// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three} +// e.g., pairs with custom projection: {1:one, 2:two, 3:three} +template +void print(const std::string_view rem, R &&range, Projection projection = exe::identity>) +{ + std::cout << rem << '{'; + std::ranges::for_each( + range, + [O = 0](const auto &o) mutable + { std::cout << (O++ ? ", " : "") << o; }, + projection); + std::cout << "}\n"; +}; + +int main() +{ + // A vector of pairs to print. + const std::vector pairs = { + {1, "one"}, + {2, "two"}, + {3, "three"}, + }; + + // Print the pairs using the default projection. + print("\tpairs with beman: ", pairs); + + return 0; +} + +``` + +Full runnable examples can be found in [`examples/`](examples/). + +## Dependencies + +### Build Environment + +This project requires at least the following to build: + +- C++17 +- CMake 3.25 +- (Test Only) GoogleTest + +You can disable building tests by setting cmake option +[`BEMAN_EXEMPLAR_BUILD_TESTS`](#beman_exemplar_build_tests) to `OFF` +when configuring the project. + +Even when tests are being built and run, some will not be compiled +unless provided compiler support **C++20** or ranges capabilities enabled. + +> [!TIP] +> +> In the logs you will be able to see if there are any examples that aren't enabled +> due to compiler capabilities or the configured C++ version. +> +> Below is an example: +> +> ```txt +> -- Looking for __cpp_lib_ranges +> -- Looking for __cpp_lib_ranges - not found +> CMake Warning at examples/CMakeLists.txt:12 (message): +> Missing range support! Skip: identity_as_default_projection +> +> +> Examples to be built: identity_direct_usage +> ``` + +### Supported Platforms + +This project officially supports: + +- GNU GCC Compiler \[version 12-14\] +- LLVM Clang++ Compiler \[version 17-20\] +- AppleClang compiler on Mac OS +- MSVC compiler on Windows + +> [!NOTE] +> +> Versions outside of this range would likely work as well, +> especially if you're using a version above the given range +> (e.g. HEAD/ nightly). +> These development environments are verified using our CI configuration. + +## Development + +### Develop using GitHub Codespace + +This project supports [GitHub Codespace](https://github.com/features/codespaces) +via [Development Containers](https://containers.dev/), +which allows rapid development and instant hacking in your browser. +We recommend you using GitHub codespace to explore this project as this +requires minimal setup. + +You can create a codespace for this project by clicking this badge: + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bemanproject/exemplar) + +For more detailed documentation regarding creating and developing inside of +GitHub codespaces, please reference [this doc](https://docs.github.com/en/codespaces/). + +> [!NOTE] +> +> The codespace container may take up to 5 minutes to build and spin-up, +> this is normal as we need to build a custom docker container to setup +> an environment appropriate for beman projects. + +### Develop locally on your machines + +
+ For Linux based systems + +Beman libraries require [recent versions of CMake](#build-environment), +we advise you to download CMake directly from [CMake's website](https://cmake.org/download/) +or install it via the [Kitware apt library](https://apt.kitware.com/). + +A [supported compiler](#supported-platforms) should be available from your package manager. +Alternatively you could use an install script from official compiler vendors. + +Here is an example of how to install the latest stable version of clang +as per [the official LLVM install guide](https://apt.llvm.org/). + +```bash +bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" +``` + +If the included test suite is being built and run, a GoogleTest library will be +required. Here is an example of installing GoogleTest on a Debian-based Linux +environment: + +```bash +apt install libgtest-dev +``` + +The precise command and package name will vary depending on the Linux OS you are +using. Be sure to consult documentation and the package repository for the system +you are using. + +
+ +
+ For MacOS based systems + +Beman libraries require [recent versions of CMake](#build-environment). +You can use [`Homebrew`](https://brew.sh/) to install the latest major version of CMake. + +```bash +brew install cmake +``` + +A [supported compiler](#supported-platforms) is also available from brew. + +For example, you can install the latest major release of Clang as: + +```bash +brew install llvm +``` + +
+ +
+ For Windows + +To build Beman libraries, you will need the MSVC compiler. MSVC can be obtained +by installing Visual Studio; the free Visual Studio 2022 Community Edition can +be downloaded from +[Microsoft](https://visualstudio.microsoft.com/vs/community/). + +After Visual Studio has been installed, you can launch "Developer PowerShell for +VS 2022" by typing it into Windows search bar. This shell environment will +provide CMake, Ninja, and MSVC, allowing you to build the library and run the +tests. + +Note that you will need to use FetchContent to build GoogleTest. To do so, +please see the instructions in the "Build GoogleTest dependency from github.com" +dropdown in the [Project specific configure +arguments](#project-specific-configure-arguments) section. + +
+ +### Configure and Build the Project Using CMake Presets + +This project recommends using [CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html) +to configure, build and test the project. +Appropriate presets for major compilers have been included by default. +You can use `cmake --list-presets` to see all available presets. + +Here is an example to invoke the `gcc-debug` preset. + +```shell +cmake --workflow --preset gcc-debug +``` + +Generally, there are two kinds of presets, `debug` and `release`. + +The `debug` presets are designed to aid development, so it has debugging +instrumentation enabled and as many sanitizers turned on as possible. + +> [!NOTE] +> +> The set of sanitizer supports are different across compilers. +> You can checkout the exact set of compiler arguments by looking at the toolchain +> files under the [`cmake`](cmake/) directory. + +The `release` presets are designed for use in production environments, +thus they have the highest optimization turned on (e.g. `O3`). + +### Configure and Build Manually + +While [CMake Presets](#configure-and-build-the-project-using-cmake-presets) are +convenient, you might want to set different configuration or compiler arguments +than any provided preset supports. + +To configure, build and test the project with extra arguments, +you can run this set of commands. + +```bash +cmake -B build -S . -DCMAKE_CXX_STANDARD=20 # Your extra arguments here. +cmake --build build +ctest --test-dir build +``` + +> [!IMPORTANT] +> +> Beman projects are +> [passive projects](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#cmake), +> therefore, +> you will need to specify the C++ version via `CMAKE_CXX_STANDARD` +> when manually configuring the project. + +### Finding and Fetching GTest from GitHub + +If you do not have GoogleTest installed on your development system, you may +optionally configure this project to download a known-compatible release of +GoogleTest from source and build it as well. + +Example commands: + +```shell +cmake -B build -S . \ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake \ + -DCMAKE_CXX_STANDARD=20 +cmake --build build --target all +cmake --build build --target test +``` + +The precise version of GoogleTest that will be used is maintained in +`./lockfile.json`. + +### Project specific configure arguments + +When configuring the project manually, +you can pass an array of project specific CMake configs to customize your build. + +Project specific options are prefixed with `BEMAN_EXEMPLAR`. +You can see the list of available options with: + +```bash +cmake -LH | grep "BEMAN_EXEMPLAR" -C 2 +``` + +
+ + Details of CMake arguments. + +#### `BEMAN_EXEMPLAR_BUILD_TESTS` + +Enable building tests and test infrastructure. Default: ON. +Values: { ON, OFF }. + +You can configure the project to have this option turned off via: + +```bash +cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF +``` + +> [!TIP] +> Because this project requires Google Tests as part of its development +> dependency, +> disable building tests avoids the project from pulling Google Tests from +> GitHub. + +#### `BEMAN_EXEMPLAR_BUILD_EXAMPLES` + +Enable building examples. Default: ON. Values: { ON, OFF }. + +
+ +## Integrate beman.exemplar into your project + +To use `beman.exemplar` in your C++ project, +include an appropriate `beman.exemplar` header from your source code. + +```c++ +#include +``` + +> [!NOTE] +> +> `beman.exemplar` headers are to be included with the `beman/exemplar/` directories prefixed. +> It is not supported to alter include search paths to spell the include target another way. For instance, +> `#include ` is not a supported interface. + +How you will link your project against `beman.exemplar` will depend on your build system. +CMake instructions are provided in following sections. + +### Linking your project to beman.exemplar with CMake + +For CMake based projects, +you will need to use the `beman.exemplar` CMake module +to define the `beman::exemplar` CMake target: + +```cmake +find_package(beman.exemplar REQUIRED) +``` + +You will also need to add `beman::exemplar` to the link libraries of +any libraries or executables that include beman.exemplar's header file. + +```cmake +target_link_libraries(yourlib PUBLIC beman::exemplar) +``` + +### Produce beman.exemplar static library locally + +You can include exemplar's headers locally +by producing a static `libbeman.exemplar.a` library. + +```bash +cmake --workflow --preset gcc-release +cmake --install build/gcc-release --prefix /opt/beman.exemplar +``` + +This will generate such directory structure at `/opt/beman.exemplar`. + +```txt +/opt/beman.exemplar +├── include +│ └── beman +│ └── exemplar +│ └── identity.hpp +└── lib + └── libbeman.exemplar.a +``` + +## Contributing + +Please do! +You encourage you to checkout our [contributor's guide](docs/README.md). +Issues and pull requests are appreciated. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt new file mode 100644 index 00000000..fe1bce03 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.25) + +project( + beman.exemplar # CMake Project Name, which is also the name of the top-level + # targets (e.g., library, executable, etc.). + DESCRIPTION "A Beman Library Exemplar" + LANGUAGES CXX + VERSION 2.1.1 +) + +# [CMAKE.SKIP_TESTS] +option( + BEMAN_EXEMPLAR_BUILD_TESTS + "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +# [CMAKE.SKIP_EXAMPLES] +option( + BEMAN_EXEMPLAR_BUILD_EXAMPLES + "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +option( + BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE + "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +include(CTest) + +add_subdirectory(src/beman/exemplar) + +if(BEMAN_EXEMPLAR_BUILD_TESTS) + add_subdirectory(tests/beman/exemplar) +endif() + +if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE new file mode 100644 index 00000000..0873f35a --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE @@ -0,0 +1,234 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + 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. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md new file mode 100644 index 00000000..1e714a1f --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md @@ -0,0 +1,399 @@ +# 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/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. + +**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) + +## Usage + +`std::identity` is a function object type whose `operator()` returns its argument unchanged. +`std::identity` serves as the default projection in constrained algorithms. +Its direct usage is usually not needed. + +### Usage: default projection in constrained algorithms + +The following code snippet illustrates how we can achieve a default projection using `beman::exemplar::identity`: + +```cpp +#include + +namespace exe = beman::exemplar; + +// Class with a pair of values. +struct Pair +{ + int n; + std::string s; + + // Output the pair in the form {n, s}. + // Used by the range-printer if no custom projection is provided (default: identity projection). + friend std::ostream &operator<<(std::ostream &os, const Pair &p) + { + return os << "Pair" << '{' << p.n << ", " << p.s << '}'; + } +}; + +// A range-printer that can print projected (modified) elements of a range. +// All the elements of the range are printed in the form {element1, element2, ...}. +// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three} +// e.g., pairs with custom projection: {1:one, 2:two, 3:three} +template +void print(const std::string_view rem, R &&range, Projection projection = exe::identity>) +{ + std::cout << rem << '{'; + std::ranges::for_each( + range, + [O = 0](const auto &o) mutable + { std::cout << (O++ ? ", " : "") << o; }, + projection); + std::cout << "}\n"; +}; + +int main() +{ + // A vector of pairs to print. + const std::vector pairs = { + {1, "one"}, + {2, "two"}, + {3, "three"}, + }; + + // Print the pairs using the default projection. + print("\tpairs with beman: ", pairs); + + return 0; +} + +``` + +Full runnable examples can be found in [`examples/`](examples/). + +## Dependencies + +### Build Environment + +This project requires at least the following to build: + +- C++17 +- CMake 3.25 +- (Test Only) GoogleTest + +You can disable building tests by setting cmake option +[`BEMAN_EXEMPLAR_BUILD_TESTS`](#beman_exemplar_build_tests) to `OFF` +when configuring the project. + +Even when tests are being built and run, some will not be compiled +unless provided compiler support **C++20** or ranges capabilities enabled. + +> [!TIP] +> +> In the logs you will be able to see if there are any examples that aren't enabled +> due to compiler capabilities or the configured C++ version. +> +> Below is an example: +> +> ```txt +> -- Looking for __cpp_lib_ranges +> -- Looking for __cpp_lib_ranges - not found +> CMake Warning at examples/CMakeLists.txt:12 (message): +> Missing range support! Skip: identity_as_default_projection +> +> +> Examples to be built: identity_direct_usage +> ``` + +### Supported Platforms + +This project officially supports: + +- GNU GCC Compiler \[version 12-14\] +- LLVM Clang++ Compiler \[version 17-20\] +- AppleClang compiler on Mac OS +- MSVC compiler on Windows + +> [!NOTE] +> +> Versions outside of this range would likely work as well, +> especially if you're using a version above the given range +> (e.g. HEAD/ nightly). +> These development environments are verified using our CI configuration. + +## Development + +### Develop using GitHub Codespace + +This project supports [GitHub Codespace](https://github.com/features/codespaces) +via [Development Containers](https://containers.dev/), +which allows rapid development and instant hacking in your browser. +We recommend you using GitHub codespace to explore this project as this +requires minimal setup. + +You can create a codespace for this project by clicking this badge: + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bemanproject/exemplar) + +For more detailed documentation regarding creating and developing inside of +GitHub codespaces, please reference [this doc](https://docs.github.com/en/codespaces/). + +> [!NOTE] +> +> The codespace container may take up to 5 minutes to build and spin-up, +> this is normal as we need to build a custom docker container to setup +> an environment appropriate for beman projects. + +### Develop locally on your machines + +
+ For Linux based systems + +Beman libraries require [recent versions of CMake](#build-environment), +we advise you to download CMake directly from [CMake's website](https://cmake.org/download/) +or install it via the [Kitware apt library](https://apt.kitware.com/). + +A [supported compiler](#supported-platforms) should be available from your package manager. +Alternatively you could use an install script from official compiler vendors. + +Here is an example of how to install the latest stable version of clang +as per [the official LLVM install guide](https://apt.llvm.org/). + +```bash +bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" +``` + +If the included test suite is being built and run, a GoogleTest library will be +required. Here is an example of installing GoogleTest on a Debian-based Linux +environment: + +```bash +apt install libgtest-dev +``` + +The precise command and package name will vary depending on the Linux OS you are +using. Be sure to consult documentation and the package repository for the system +you are using. + +
+ +
+ For MacOS based systems + +Beman libraries require [recent versions of CMake](#build-environment). +You can use [`Homebrew`](https://brew.sh/) to install the latest major version of CMake. + +```bash +brew install cmake +``` + +A [supported compiler](#supported-platforms) is also available from brew. + +For example, you can install the latest major release of Clang as: + +```bash +brew install llvm +``` + +
+ +
+ For Windows + +To build Beman libraries, you will need the MSVC compiler. MSVC can be obtained +by installing Visual Studio; the free Visual Studio 2022 Community Edition can +be downloaded from +[Microsoft](https://visualstudio.microsoft.com/vs/community/). + +After Visual Studio has been installed, you can launch "Developer PowerShell for +VS 2022" by typing it into Windows search bar. This shell environment will +provide CMake, Ninja, and MSVC, allowing you to build the library and run the +tests. + +Note that you will need to use FetchContent to build GoogleTest. To do so, +please see the instructions in the "Build GoogleTest dependency from github.com" +dropdown in the [Project specific configure +arguments](#project-specific-configure-arguments) section. + +
+ +### Configure and Build the Project Using CMake Presets + +This project recommends using [CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html) +to configure, build and test the project. +Appropriate presets for major compilers have been included by default. +You can use `cmake --list-presets` to see all available presets. + +Here is an example to invoke the `gcc-debug` preset. + +```shell +cmake --workflow --preset gcc-debug +``` + +Generally, there are two kinds of presets, `debug` and `release`. + +The `debug` presets are designed to aid development, so it has debugging +instrumentation enabled and as many sanitizers turned on as possible. + +> [!NOTE] +> +> The set of sanitizer supports are different across compilers. +> You can checkout the exact set of compiler arguments by looking at the toolchain +> files under the [`cmake`](cmake/) directory. + +The `release` presets are designed for use in production environments, +thus they have the highest optimization turned on (e.g. `O3`). + +### Configure and Build Manually + +While [CMake Presets](#configure-and-build-the-project-using-cmake-presets) are +convenient, you might want to set different configuration or compiler arguments +than any provided preset supports. + +To configure, build and test the project with extra arguments, +you can run this set of commands. + +```bash +cmake -B build -S . -DCMAKE_CXX_STANDARD=20 # Your extra arguments here. +cmake --build build +ctest --test-dir build +``` + +> [!IMPORTANT] +> +> Beman projects are +> [passive projects](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#cmake), +> therefore, +> you will need to specify the C++ version via `CMAKE_CXX_STANDARD` +> when manually configuring the project. + +### Finding and Fetching GTest from GitHub + +If you do not have GoogleTest installed on your development system, you may +optionally configure this project to download a known-compatible release of +GoogleTest from source and build it as well. + +Example commands: + +```shell +cmake -B build -S . \ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake \ + -DCMAKE_CXX_STANDARD=20 +cmake --build build --target all +cmake --build build --target test +``` + +The precise version of GoogleTest that will be used is maintained in +`./lockfile.json`. + +### Project specific configure arguments + +When configuring the project manually, +you can pass an array of project specific CMake configs to customize your build. + +Project specific options are prefixed with `BEMAN_EXEMPLAR`. +You can see the list of available options with: + +```bash +cmake -LH | grep "BEMAN_EXEMPLAR" -C 2 +``` + +
+ + Details of CMake arguments. + +#### `BEMAN_EXEMPLAR_BUILD_TESTS` + +Enable building tests and test infrastructure. Default: ON. +Values: { ON, OFF }. + +You can configure the project to have this option turned off via: + +```bash +cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF +``` + +> [!TIP] +> Because this project requires Google Tests as part of its development +> dependency, +> disable building tests avoids the project from pulling Google Tests from +> GitHub. + +#### `BEMAN_EXEMPLAR_BUILD_EXAMPLES` + +Enable building examples. Default: ON. Values: { ON, OFF }. + +
+ +## Integrate beman.exemplar into your project + +To use `beman.exemplar` in your C++ project, +include an appropriate `beman.exemplar` header from your source code. + +```c++ +#include +``` + +> [!NOTE] +> +> `beman.exemplar` headers are to be included with the `beman/exemplar/` directories prefixed. +> It is not supported to alter include search paths to spell the include target another way. For instance, +> `#include ` is not a supported interface. + +How you will link your project against `beman.exemplar` will depend on your build system. +CMake instructions are provided in following sections. + +### Linking your project to beman.exemplar with CMake + +For CMake based projects, +you will need to use the `beman.exemplar` CMake module +to define the `beman::exemplar` CMake target: + +```cmake +find_package(beman.exemplar REQUIRED) +``` + +You will also need to add `beman::exemplar` to the link libraries of +any libraries or executables that include beman.exemplar's header file. + +```cmake +target_link_libraries(yourlib PUBLIC beman::exemplar) +``` + +### Produce beman.exemplar static library locally + +You can include exemplar's headers locally +by producing a static `libbeman.exemplar.a` library. + +```bash +cmake --workflow --preset gcc-release +cmake --install build/gcc-release --prefix /opt/beman.exemplar +``` + +This will generate such directory structure at `/opt/beman.exemplar`. + +```txt +/opt/beman.exemplar +├── include +│ └── beman +│ └── exemplar +│ └── identity.hpp +└── lib + └── libbeman.exemplar.a +``` + +## Contributing + +Please do! +You encourage you to checkout our [contributor's guide](docs/README.md). +Issues and pull requests are appreciated. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt new file mode 100644 index 00000000..fe1bce03 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.25) + +project( + beman.exemplar # CMake Project Name, which is also the name of the top-level + # targets (e.g., library, executable, etc.). + DESCRIPTION "A Beman Library Exemplar" + LANGUAGES CXX + VERSION 2.1.1 +) + +# [CMAKE.SKIP_TESTS] +option( + BEMAN_EXEMPLAR_BUILD_TESTS + "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +# [CMAKE.SKIP_EXAMPLES] +option( + BEMAN_EXEMPLAR_BUILD_EXAMPLES + "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +option( + BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE + "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +include(CTest) + +add_subdirectory(src/beman/exemplar) + +if(BEMAN_EXEMPLAR_BUILD_TESTS) + add_subdirectory(tests/beman/exemplar) +endif() + +if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py new file mode 100644 index 00000000..51ff6271 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -0,0 +1,60 @@ +#!/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_fix_inplace_for_each_file_path, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.toplevel import ( + ToplevelCmakeCheck, +) + +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 CMakeLists.txt pass the check. + """ + valid_cmake_paths = [ + Path(f"{valid_prefix}/complete_repo/"), + Path(f"{valid_prefix}/repo_with_cmake/"), + ] + + 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 without CMakeLists.txt pass the check. + """ + invalid_cmake_paths = [ + Path(f"{invalid_prefix}/empty_repo/"), + Path(f"{invalid_prefix}/repo_without_cmake/"), + ] + + 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 From 67fbda021001d09413bfbff49538665b218fa9f9 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 9 Jul 2025 15:54:48 +0300 Subject: [PATCH 276/371] [beman-tidy] Run linter --- .../tests/lib/checks/beman_standard/toplevel/test_toplevel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 51ff6271..d9951ae5 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -6,12 +6,11 @@ from tests.utils.path_runners import ( run_check_for_each_path, - run_fix_inplace_for_each_file_path, ) # Actual tested checks. from beman_tidy.lib.checks.beman_standard.toplevel import ( - ToplevelCmakeCheck, + ToplevelCmakeCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/toplevel/data" From 5bee8d110e0249522e1708ab2ac5c14319837c7b Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 9 Jul 2025 16:04:09 +0300 Subject: [PATCH 277/371] [beman-tidy] Run tests --- tools/beman-tidy/tests/utils/path_runners.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 74ab9b6f..a8f29ff0 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -22,18 +22,18 @@ 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) - else: + if os.path.isfile(path): # For file checks, set the path directly on the check instance check_instance = check_class(repo_info, beman_standard_check_config) check_instance.path = Path(path) + else: + # 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.log_level = True - if not os.path.isdir(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}" From 197b5fc36b46fd5c891c50bfdc92324f5e6321ae Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 9 Jul 2025 17:19:00 +0300 Subject: [PATCH 278/371] [beman-tidy] Updated valid and invalid test cases --- .../invalid/invalid-CMAKE1/CMakeLists.txt | 0 .../data/invalid/invalid-CMAKE1/LICENSE | 1 + .../data/invalid/invalid-CMAKE1/README.md | 1 + .../data/invalid/invalid-CMAKE2/LICENSE | 1 + .../data/invalid/invalid-CMAKE2/README.md | 1 + .../invalid-CMAKE2/cmake/CMakeLists.txt | 1 + .../data/invalid/missing-CMAKE/LICENSE | 1 + .../data/invalid/missing-CMAKE/README.md | 1 + .../data/invalid/repo_without_cmake/LICENSE | 234 ---------- .../data/invalid/repo_without_cmake/README.md | 399 ------------------ .../data/valid/complete_repo/CMakeLists.txt | 43 -- .../toplevel/data/valid/complete_repo/LICENSE | 234 ---------- .../data/valid/complete_repo/README.md | 399 ------------------ .../data/valid/exemplar/CMakeLists.txt | 1 + .../toplevel/data/valid/exemplar/LICENSE | 1 + .../toplevel/data/valid/exemplar/README.md | 1 + .../data/valid/repo_with_cmake/CMakeLists.txt | 43 -- .../beman_standard/toplevel/test_toplevel.py | 10 +- 18 files changed, 15 insertions(+), 1357 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt new file mode 100644 index 00000000..3e4f4829 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt @@ -0,0 +1 @@ +Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE deleted file mode 100644 index 0873f35a..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/LICENSE +++ /dev/null @@ -1,234 +0,0 @@ -============================================================================== -The Beman Project is under the Apache License v2.0 with LLVM Exceptions: -============================================================================== - - 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. - -============================================================================== -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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md deleted file mode 100644 index 1e714a1f..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo_without_cmake/README.md +++ /dev/null @@ -1,399 +0,0 @@ -# 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/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. - -**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) - -## Usage - -`std::identity` is a function object type whose `operator()` returns its argument unchanged. -`std::identity` serves as the default projection in constrained algorithms. -Its direct usage is usually not needed. - -### Usage: default projection in constrained algorithms - -The following code snippet illustrates how we can achieve a default projection using `beman::exemplar::identity`: - -```cpp -#include - -namespace exe = beman::exemplar; - -// Class with a pair of values. -struct Pair -{ - int n; - std::string s; - - // Output the pair in the form {n, s}. - // Used by the range-printer if no custom projection is provided (default: identity projection). - friend std::ostream &operator<<(std::ostream &os, const Pair &p) - { - return os << "Pair" << '{' << p.n << ", " << p.s << '}'; - } -}; - -// A range-printer that can print projected (modified) elements of a range. -// All the elements of the range are printed in the form {element1, element2, ...}. -// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three} -// e.g., pairs with custom projection: {1:one, 2:two, 3:three} -template -void print(const std::string_view rem, R &&range, Projection projection = exe::identity>) -{ - std::cout << rem << '{'; - std::ranges::for_each( - range, - [O = 0](const auto &o) mutable - { std::cout << (O++ ? ", " : "") << o; }, - projection); - std::cout << "}\n"; -}; - -int main() -{ - // A vector of pairs to print. - const std::vector pairs = { - {1, "one"}, - {2, "two"}, - {3, "three"}, - }; - - // Print the pairs using the default projection. - print("\tpairs with beman: ", pairs); - - return 0; -} - -``` - -Full runnable examples can be found in [`examples/`](examples/). - -## Dependencies - -### Build Environment - -This project requires at least the following to build: - -- C++17 -- CMake 3.25 -- (Test Only) GoogleTest - -You can disable building tests by setting cmake option -[`BEMAN_EXEMPLAR_BUILD_TESTS`](#beman_exemplar_build_tests) to `OFF` -when configuring the project. - -Even when tests are being built and run, some will not be compiled -unless provided compiler support **C++20** or ranges capabilities enabled. - -> [!TIP] -> -> In the logs you will be able to see if there are any examples that aren't enabled -> due to compiler capabilities or the configured C++ version. -> -> Below is an example: -> -> ```txt -> -- Looking for __cpp_lib_ranges -> -- Looking for __cpp_lib_ranges - not found -> CMake Warning at examples/CMakeLists.txt:12 (message): -> Missing range support! Skip: identity_as_default_projection -> -> -> Examples to be built: identity_direct_usage -> ``` - -### Supported Platforms - -This project officially supports: - -- GNU GCC Compiler \[version 12-14\] -- LLVM Clang++ Compiler \[version 17-20\] -- AppleClang compiler on Mac OS -- MSVC compiler on Windows - -> [!NOTE] -> -> Versions outside of this range would likely work as well, -> especially if you're using a version above the given range -> (e.g. HEAD/ nightly). -> These development environments are verified using our CI configuration. - -## Development - -### Develop using GitHub Codespace - -This project supports [GitHub Codespace](https://github.com/features/codespaces) -via [Development Containers](https://containers.dev/), -which allows rapid development and instant hacking in your browser. -We recommend you using GitHub codespace to explore this project as this -requires minimal setup. - -You can create a codespace for this project by clicking this badge: - -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bemanproject/exemplar) - -For more detailed documentation regarding creating and developing inside of -GitHub codespaces, please reference [this doc](https://docs.github.com/en/codespaces/). - -> [!NOTE] -> -> The codespace container may take up to 5 minutes to build and spin-up, -> this is normal as we need to build a custom docker container to setup -> an environment appropriate for beman projects. - -### Develop locally on your machines - -
- For Linux based systems - -Beman libraries require [recent versions of CMake](#build-environment), -we advise you to download CMake directly from [CMake's website](https://cmake.org/download/) -or install it via the [Kitware apt library](https://apt.kitware.com/). - -A [supported compiler](#supported-platforms) should be available from your package manager. -Alternatively you could use an install script from official compiler vendors. - -Here is an example of how to install the latest stable version of clang -as per [the official LLVM install guide](https://apt.llvm.org/). - -```bash -bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" -``` - -If the included test suite is being built and run, a GoogleTest library will be -required. Here is an example of installing GoogleTest on a Debian-based Linux -environment: - -```bash -apt install libgtest-dev -``` - -The precise command and package name will vary depending on the Linux OS you are -using. Be sure to consult documentation and the package repository for the system -you are using. - -
- -
- For MacOS based systems - -Beman libraries require [recent versions of CMake](#build-environment). -You can use [`Homebrew`](https://brew.sh/) to install the latest major version of CMake. - -```bash -brew install cmake -``` - -A [supported compiler](#supported-platforms) is also available from brew. - -For example, you can install the latest major release of Clang as: - -```bash -brew install llvm -``` - -
- -
- For Windows - -To build Beman libraries, you will need the MSVC compiler. MSVC can be obtained -by installing Visual Studio; the free Visual Studio 2022 Community Edition can -be downloaded from -[Microsoft](https://visualstudio.microsoft.com/vs/community/). - -After Visual Studio has been installed, you can launch "Developer PowerShell for -VS 2022" by typing it into Windows search bar. This shell environment will -provide CMake, Ninja, and MSVC, allowing you to build the library and run the -tests. - -Note that you will need to use FetchContent to build GoogleTest. To do so, -please see the instructions in the "Build GoogleTest dependency from github.com" -dropdown in the [Project specific configure -arguments](#project-specific-configure-arguments) section. - -
- -### Configure and Build the Project Using CMake Presets - -This project recommends using [CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html) -to configure, build and test the project. -Appropriate presets for major compilers have been included by default. -You can use `cmake --list-presets` to see all available presets. - -Here is an example to invoke the `gcc-debug` preset. - -```shell -cmake --workflow --preset gcc-debug -``` - -Generally, there are two kinds of presets, `debug` and `release`. - -The `debug` presets are designed to aid development, so it has debugging -instrumentation enabled and as many sanitizers turned on as possible. - -> [!NOTE] -> -> The set of sanitizer supports are different across compilers. -> You can checkout the exact set of compiler arguments by looking at the toolchain -> files under the [`cmake`](cmake/) directory. - -The `release` presets are designed for use in production environments, -thus they have the highest optimization turned on (e.g. `O3`). - -### Configure and Build Manually - -While [CMake Presets](#configure-and-build-the-project-using-cmake-presets) are -convenient, you might want to set different configuration or compiler arguments -than any provided preset supports. - -To configure, build and test the project with extra arguments, -you can run this set of commands. - -```bash -cmake -B build -S . -DCMAKE_CXX_STANDARD=20 # Your extra arguments here. -cmake --build build -ctest --test-dir build -``` - -> [!IMPORTANT] -> -> Beman projects are -> [passive projects](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#cmake), -> therefore, -> you will need to specify the C++ version via `CMAKE_CXX_STANDARD` -> when manually configuring the project. - -### Finding and Fetching GTest from GitHub - -If you do not have GoogleTest installed on your development system, you may -optionally configure this project to download a known-compatible release of -GoogleTest from source and build it as well. - -Example commands: - -```shell -cmake -B build -S . \ - -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake \ - -DCMAKE_CXX_STANDARD=20 -cmake --build build --target all -cmake --build build --target test -``` - -The precise version of GoogleTest that will be used is maintained in -`./lockfile.json`. - -### Project specific configure arguments - -When configuring the project manually, -you can pass an array of project specific CMake configs to customize your build. - -Project specific options are prefixed with `BEMAN_EXEMPLAR`. -You can see the list of available options with: - -```bash -cmake -LH | grep "BEMAN_EXEMPLAR" -C 2 -``` - -
- - Details of CMake arguments. - -#### `BEMAN_EXEMPLAR_BUILD_TESTS` - -Enable building tests and test infrastructure. Default: ON. -Values: { ON, OFF }. - -You can configure the project to have this option turned off via: - -```bash -cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF -``` - -> [!TIP] -> Because this project requires Google Tests as part of its development -> dependency, -> disable building tests avoids the project from pulling Google Tests from -> GitHub. - -#### `BEMAN_EXEMPLAR_BUILD_EXAMPLES` - -Enable building examples. Default: ON. Values: { ON, OFF }. - -
- -## Integrate beman.exemplar into your project - -To use `beman.exemplar` in your C++ project, -include an appropriate `beman.exemplar` header from your source code. - -```c++ -#include -``` - -> [!NOTE] -> -> `beman.exemplar` headers are to be included with the `beman/exemplar/` directories prefixed. -> It is not supported to alter include search paths to spell the include target another way. For instance, -> `#include ` is not a supported interface. - -How you will link your project against `beman.exemplar` will depend on your build system. -CMake instructions are provided in following sections. - -### Linking your project to beman.exemplar with CMake - -For CMake based projects, -you will need to use the `beman.exemplar` CMake module -to define the `beman::exemplar` CMake target: - -```cmake -find_package(beman.exemplar REQUIRED) -``` - -You will also need to add `beman::exemplar` to the link libraries of -any libraries or executables that include beman.exemplar's header file. - -```cmake -target_link_libraries(yourlib PUBLIC beman::exemplar) -``` - -### Produce beman.exemplar static library locally - -You can include exemplar's headers locally -by producing a static `libbeman.exemplar.a` library. - -```bash -cmake --workflow --preset gcc-release -cmake --install build/gcc-release --prefix /opt/beman.exemplar -``` - -This will generate such directory structure at `/opt/beman.exemplar`. - -```txt -/opt/beman.exemplar -├── include -│ └── beman -│ └── exemplar -│ └── identity.hpp -└── lib - └── libbeman.exemplar.a -``` - -## Contributing - -Please do! -You encourage you to checkout our [contributor's guide](docs/README.md). -Issues and pull requests are appreciated. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt deleted file mode 100644 index fe1bce03..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required(VERSION 3.25) - -project( - beman.exemplar # CMake Project Name, which is also the name of the top-level - # targets (e.g., library, executable, etc.). - DESCRIPTION "A Beman Library Exemplar" - LANGUAGES CXX - VERSION 2.1.1 -) - -# [CMAKE.SKIP_TESTS] -option( - BEMAN_EXEMPLAR_BUILD_TESTS - "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -# [CMAKE.SKIP_EXAMPLES] -option( - BEMAN_EXEMPLAR_BUILD_EXAMPLES - "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -option( - BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE - "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -include(CTest) - -add_subdirectory(src/beman/exemplar) - -if(BEMAN_EXEMPLAR_BUILD_TESTS) - add_subdirectory(tests/beman/exemplar) -endif() - -if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) - add_subdirectory(examples) -endif() diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE deleted file mode 100644 index 0873f35a..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/LICENSE +++ /dev/null @@ -1,234 +0,0 @@ -============================================================================== -The Beman Project is under the Apache License v2.0 with LLVM Exceptions: -============================================================================== - - 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. - -============================================================================== -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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md deleted file mode 100644 index 1e714a1f..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/complete_repo/README.md +++ /dev/null @@ -1,399 +0,0 @@ -# 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/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. - -**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) - -## Usage - -`std::identity` is a function object type whose `operator()` returns its argument unchanged. -`std::identity` serves as the default projection in constrained algorithms. -Its direct usage is usually not needed. - -### Usage: default projection in constrained algorithms - -The following code snippet illustrates how we can achieve a default projection using `beman::exemplar::identity`: - -```cpp -#include - -namespace exe = beman::exemplar; - -// Class with a pair of values. -struct Pair -{ - int n; - std::string s; - - // Output the pair in the form {n, s}. - // Used by the range-printer if no custom projection is provided (default: identity projection). - friend std::ostream &operator<<(std::ostream &os, const Pair &p) - { - return os << "Pair" << '{' << p.n << ", " << p.s << '}'; - } -}; - -// A range-printer that can print projected (modified) elements of a range. -// All the elements of the range are printed in the form {element1, element2, ...}. -// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three} -// e.g., pairs with custom projection: {1:one, 2:two, 3:three} -template -void print(const std::string_view rem, R &&range, Projection projection = exe::identity>) -{ - std::cout << rem << '{'; - std::ranges::for_each( - range, - [O = 0](const auto &o) mutable - { std::cout << (O++ ? ", " : "") << o; }, - projection); - std::cout << "}\n"; -}; - -int main() -{ - // A vector of pairs to print. - const std::vector pairs = { - {1, "one"}, - {2, "two"}, - {3, "three"}, - }; - - // Print the pairs using the default projection. - print("\tpairs with beman: ", pairs); - - return 0; -} - -``` - -Full runnable examples can be found in [`examples/`](examples/). - -## Dependencies - -### Build Environment - -This project requires at least the following to build: - -- C++17 -- CMake 3.25 -- (Test Only) GoogleTest - -You can disable building tests by setting cmake option -[`BEMAN_EXEMPLAR_BUILD_TESTS`](#beman_exemplar_build_tests) to `OFF` -when configuring the project. - -Even when tests are being built and run, some will not be compiled -unless provided compiler support **C++20** or ranges capabilities enabled. - -> [!TIP] -> -> In the logs you will be able to see if there are any examples that aren't enabled -> due to compiler capabilities or the configured C++ version. -> -> Below is an example: -> -> ```txt -> -- Looking for __cpp_lib_ranges -> -- Looking for __cpp_lib_ranges - not found -> CMake Warning at examples/CMakeLists.txt:12 (message): -> Missing range support! Skip: identity_as_default_projection -> -> -> Examples to be built: identity_direct_usage -> ``` - -### Supported Platforms - -This project officially supports: - -- GNU GCC Compiler \[version 12-14\] -- LLVM Clang++ Compiler \[version 17-20\] -- AppleClang compiler on Mac OS -- MSVC compiler on Windows - -> [!NOTE] -> -> Versions outside of this range would likely work as well, -> especially if you're using a version above the given range -> (e.g. HEAD/ nightly). -> These development environments are verified using our CI configuration. - -## Development - -### Develop using GitHub Codespace - -This project supports [GitHub Codespace](https://github.com/features/codespaces) -via [Development Containers](https://containers.dev/), -which allows rapid development and instant hacking in your browser. -We recommend you using GitHub codespace to explore this project as this -requires minimal setup. - -You can create a codespace for this project by clicking this badge: - -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bemanproject/exemplar) - -For more detailed documentation regarding creating and developing inside of -GitHub codespaces, please reference [this doc](https://docs.github.com/en/codespaces/). - -> [!NOTE] -> -> The codespace container may take up to 5 minutes to build and spin-up, -> this is normal as we need to build a custom docker container to setup -> an environment appropriate for beman projects. - -### Develop locally on your machines - -
- For Linux based systems - -Beman libraries require [recent versions of CMake](#build-environment), -we advise you to download CMake directly from [CMake's website](https://cmake.org/download/) -or install it via the [Kitware apt library](https://apt.kitware.com/). - -A [supported compiler](#supported-platforms) should be available from your package manager. -Alternatively you could use an install script from official compiler vendors. - -Here is an example of how to install the latest stable version of clang -as per [the official LLVM install guide](https://apt.llvm.org/). - -```bash -bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" -``` - -If the included test suite is being built and run, a GoogleTest library will be -required. Here is an example of installing GoogleTest on a Debian-based Linux -environment: - -```bash -apt install libgtest-dev -``` - -The precise command and package name will vary depending on the Linux OS you are -using. Be sure to consult documentation and the package repository for the system -you are using. - -
- -
- For MacOS based systems - -Beman libraries require [recent versions of CMake](#build-environment). -You can use [`Homebrew`](https://brew.sh/) to install the latest major version of CMake. - -```bash -brew install cmake -``` - -A [supported compiler](#supported-platforms) is also available from brew. - -For example, you can install the latest major release of Clang as: - -```bash -brew install llvm -``` - -
- -
- For Windows - -To build Beman libraries, you will need the MSVC compiler. MSVC can be obtained -by installing Visual Studio; the free Visual Studio 2022 Community Edition can -be downloaded from -[Microsoft](https://visualstudio.microsoft.com/vs/community/). - -After Visual Studio has been installed, you can launch "Developer PowerShell for -VS 2022" by typing it into Windows search bar. This shell environment will -provide CMake, Ninja, and MSVC, allowing you to build the library and run the -tests. - -Note that you will need to use FetchContent to build GoogleTest. To do so, -please see the instructions in the "Build GoogleTest dependency from github.com" -dropdown in the [Project specific configure -arguments](#project-specific-configure-arguments) section. - -
- -### Configure and Build the Project Using CMake Presets - -This project recommends using [CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html) -to configure, build and test the project. -Appropriate presets for major compilers have been included by default. -You can use `cmake --list-presets` to see all available presets. - -Here is an example to invoke the `gcc-debug` preset. - -```shell -cmake --workflow --preset gcc-debug -``` - -Generally, there are two kinds of presets, `debug` and `release`. - -The `debug` presets are designed to aid development, so it has debugging -instrumentation enabled and as many sanitizers turned on as possible. - -> [!NOTE] -> -> The set of sanitizer supports are different across compilers. -> You can checkout the exact set of compiler arguments by looking at the toolchain -> files under the [`cmake`](cmake/) directory. - -The `release` presets are designed for use in production environments, -thus they have the highest optimization turned on (e.g. `O3`). - -### Configure and Build Manually - -While [CMake Presets](#configure-and-build-the-project-using-cmake-presets) are -convenient, you might want to set different configuration or compiler arguments -than any provided preset supports. - -To configure, build and test the project with extra arguments, -you can run this set of commands. - -```bash -cmake -B build -S . -DCMAKE_CXX_STANDARD=20 # Your extra arguments here. -cmake --build build -ctest --test-dir build -``` - -> [!IMPORTANT] -> -> Beman projects are -> [passive projects](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#cmake), -> therefore, -> you will need to specify the C++ version via `CMAKE_CXX_STANDARD` -> when manually configuring the project. - -### Finding and Fetching GTest from GitHub - -If you do not have GoogleTest installed on your development system, you may -optionally configure this project to download a known-compatible release of -GoogleTest from source and build it as well. - -Example commands: - -```shell -cmake -B build -S . \ - -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake \ - -DCMAKE_CXX_STANDARD=20 -cmake --build build --target all -cmake --build build --target test -``` - -The precise version of GoogleTest that will be used is maintained in -`./lockfile.json`. - -### Project specific configure arguments - -When configuring the project manually, -you can pass an array of project specific CMake configs to customize your build. - -Project specific options are prefixed with `BEMAN_EXEMPLAR`. -You can see the list of available options with: - -```bash -cmake -LH | grep "BEMAN_EXEMPLAR" -C 2 -``` - -
- - Details of CMake arguments. - -#### `BEMAN_EXEMPLAR_BUILD_TESTS` - -Enable building tests and test infrastructure. Default: ON. -Values: { ON, OFF }. - -You can configure the project to have this option turned off via: - -```bash -cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF -``` - -> [!TIP] -> Because this project requires Google Tests as part of its development -> dependency, -> disable building tests avoids the project from pulling Google Tests from -> GitHub. - -#### `BEMAN_EXEMPLAR_BUILD_EXAMPLES` - -Enable building examples. Default: ON. Values: { ON, OFF }. - -
- -## Integrate beman.exemplar into your project - -To use `beman.exemplar` in your C++ project, -include an appropriate `beman.exemplar` header from your source code. - -```c++ -#include -``` - -> [!NOTE] -> -> `beman.exemplar` headers are to be included with the `beman/exemplar/` directories prefixed. -> It is not supported to alter include search paths to spell the include target another way. For instance, -> `#include ` is not a supported interface. - -How you will link your project against `beman.exemplar` will depend on your build system. -CMake instructions are provided in following sections. - -### Linking your project to beman.exemplar with CMake - -For CMake based projects, -you will need to use the `beman.exemplar` CMake module -to define the `beman::exemplar` CMake target: - -```cmake -find_package(beman.exemplar REQUIRED) -``` - -You will also need to add `beman::exemplar` to the link libraries of -any libraries or executables that include beman.exemplar's header file. - -```cmake -target_link_libraries(yourlib PUBLIC beman::exemplar) -``` - -### Produce beman.exemplar static library locally - -You can include exemplar's headers locally -by producing a static `libbeman.exemplar.a` library. - -```bash -cmake --workflow --preset gcc-release -cmake --install build/gcc-release --prefix /opt/beman.exemplar -``` - -This will generate such directory structure at `/opt/beman.exemplar`. - -```txt -/opt/beman.exemplar -├── include -│ └── beman -│ └── exemplar -│ └── identity.hpp -└── lib - └── libbeman.exemplar.a -``` - -## Contributing - -Please do! -You encourage you to checkout our [contributor's guide](docs/README.md). -Issues and pull requests are appreciated. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt new file mode 100644 index 00000000..3e4f4829 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt @@ -0,0 +1 @@ +Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt deleted file mode 100644 index fe1bce03..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo_with_cmake/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required(VERSION 3.25) - -project( - beman.exemplar # CMake Project Name, which is also the name of the top-level - # targets (e.g., library, executable, etc.). - DESCRIPTION "A Beman Library Exemplar" - LANGUAGES CXX - VERSION 2.1.1 -) - -# [CMAKE.SKIP_TESTS] -option( - BEMAN_EXEMPLAR_BUILD_TESTS - "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -# [CMAKE.SKIP_EXAMPLES] -option( - BEMAN_EXEMPLAR_BUILD_EXAMPLES - "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -option( - BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE - "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -include(CTest) - -add_subdirectory(src/beman/exemplar) - -if(BEMAN_EXEMPLAR_BUILD_TESTS) - add_subdirectory(tests/beman/exemplar) -endif() - -if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) - add_subdirectory(examples) -endif() diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index d9951ae5..898ab823 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -23,8 +23,7 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): Test that repositories with CMakeLists.txt pass the check. """ valid_cmake_paths = [ - Path(f"{valid_prefix}/complete_repo/"), - Path(f"{valid_prefix}/repo_with_cmake/"), + Path(f"{valid_prefix}/exemplar/"), ] run_check_for_each_path( @@ -38,11 +37,12 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): def test__TOPLEVEL_CMAKE__invalid(repo_info, beman_standard_check_config): """ - Test that repositories without CMakeLists.txt pass the check. + Test that repositories without CMakeLists.txt fail the check. """ invalid_cmake_paths = [ - Path(f"{invalid_prefix}/empty_repo/"), - Path(f"{invalid_prefix}/repo_without_cmake/"), + Path(f"{invalid_prefix}/missing-CMAKE/"), + Path(f"{invalid_prefix}/invalid-CMAKE1/"), + Path(f"{invalid_prefix}/invalid-CMAKE2/"), ] run_check_for_each_path( From 91af0aaf809434e7eb3d7df254318094d243a38a Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 9 Jul 2025 17:24:26 +0300 Subject: [PATCH 279/371] [beman-tidy] Removed duplicate line --- tools/beman-tidy/tests/utils/path_runners.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index a8f29ff0..746eee11 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -22,14 +22,15 @@ 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) + if os.path.isfile(path): # For file checks, set the path directly on the check instance - check_instance = check_class(repo_info, beman_standard_check_config) check_instance.path = Path(path) - else: - # 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.log_level = True From dc798ccfd4779368e25528fbfdc429ca06ecb375 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 10 Jul 2025 13:05:41 +0300 Subject: [PATCH 280/371] [beman-tidy] CMake linter --- .../invalid-CMAKE2/cmake/CMakeLists.txt | 44 ++++++++++++++++++- .../data/valid/exemplar/CMakeLists.txt | 44 ++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt index 3e4f4829..fe1bce03 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt @@ -1 +1,43 @@ -Dummy content. Test that CMakeLists.txt is non-empty. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.25) + +project( + beman.exemplar # CMake Project Name, which is also the name of the top-level + # targets (e.g., library, executable, etc.). + DESCRIPTION "A Beman Library Exemplar" + LANGUAGES CXX + VERSION 2.1.1 +) + +# [CMAKE.SKIP_TESTS] +option( + BEMAN_EXEMPLAR_BUILD_TESTS + "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +# [CMAKE.SKIP_EXAMPLES] +option( + BEMAN_EXEMPLAR_BUILD_EXAMPLES + "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +option( + BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE + "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +include(CTest) + +add_subdirectory(src/beman/exemplar) + +if(BEMAN_EXEMPLAR_BUILD_TESTS) + add_subdirectory(tests/beman/exemplar) +endif() + +if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt index 3e4f4829..fe1bce03 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt @@ -1 +1,43 @@ -Dummy content. Test that CMakeLists.txt is non-empty. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.25) + +project( + beman.exemplar # CMake Project Name, which is also the name of the top-level + # targets (e.g., library, executable, etc.). + DESCRIPTION "A Beman Library Exemplar" + LANGUAGES CXX + VERSION 2.1.1 +) + +# [CMAKE.SKIP_TESTS] +option( + BEMAN_EXEMPLAR_BUILD_TESTS + "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +# [CMAKE.SKIP_EXAMPLES] +option( + BEMAN_EXEMPLAR_BUILD_EXAMPLES + "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +option( + BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE + "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} +) + +include(CTest) + +add_subdirectory(src/beman/exemplar) + +if(BEMAN_EXEMPLAR_BUILD_TESTS) + add_subdirectory(tests/beman/exemplar) +endif() + +if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() From cfc6f95b6754cfafe626a9a6ea196460644dbd25 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 10 Jul 2025 13:45:05 +0300 Subject: [PATCH 281/371] [beman-tidy] Added 'exclude' rule for the CMake linter --- .pre-commit-config.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3c22d577..08795ded 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,10 +2,10 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files - repo: https://github.com/codespell-project/codespell rev: v2.3.0 @@ -16,9 +16,9 @@ repos: - repo: https://github.com/BlankSpruce/gersemi rev: 0.15.1 hooks: - - id: gersemi - name: CMake linting - + - id: gersemi + name: CMake linting + exclude: ^infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/.*CMakeLists\.txt$ # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ From 6af20dc296491e8083e327ba8f3957abdb6ba294 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 10 Jul 2025 13:46:47 +0300 Subject: [PATCH 282/371] [beman-tidy ] Update test descriptions and changed CMakeLists.txt files to contain dummy content --- .../invalid-CMAKE2/cmake/CMakeLists.txt | 44 +------------------ .../data/valid/exemplar/CMakeLists.txt | 44 +------------------ .../beman_standard/toplevel/test_toplevel.py | 4 +- 3 files changed, 4 insertions(+), 88 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt index fe1bce03..33ab4df8 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt @@ -1,43 +1 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required(VERSION 3.25) - -project( - beman.exemplar # CMake Project Name, which is also the name of the top-level - # targets (e.g., library, executable, etc.). - DESCRIPTION "A Beman Library Exemplar" - LANGUAGES CXX - VERSION 2.1.1 -) - -# [CMAKE.SKIP_TESTS] -option( - BEMAN_EXEMPLAR_BUILD_TESTS - "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -# [CMAKE.SKIP_EXAMPLES] -option( - BEMAN_EXEMPLAR_BUILD_EXAMPLES - "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -option( - BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE - "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -include(CTest) - -add_subdirectory(src/beman/exemplar) - -if(BEMAN_EXEMPLAR_BUILD_TESTS) - add_subdirectory(tests/beman/exemplar) -endif() - -if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) - add_subdirectory(examples) -endif() +# Dummy content. Test that CMakeLists.txt is non-empty. \ No newline at end of file diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt index fe1bce03..33ab4df8 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt @@ -1,43 +1 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required(VERSION 3.25) - -project( - beman.exemplar # CMake Project Name, which is also the name of the top-level - # targets (e.g., library, executable, etc.). - DESCRIPTION "A Beman Library Exemplar" - LANGUAGES CXX - VERSION 2.1.1 -) - -# [CMAKE.SKIP_TESTS] -option( - BEMAN_EXEMPLAR_BUILD_TESTS - "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -# [CMAKE.SKIP_EXAMPLES] -option( - BEMAN_EXEMPLAR_BUILD_EXAMPLES - "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -option( - BEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE - "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." - ${PROJECT_IS_TOP_LEVEL} -) - -include(CTest) - -add_subdirectory(src/beman/exemplar) - -if(BEMAN_EXEMPLAR_BUILD_TESTS) - add_subdirectory(tests/beman/exemplar) -endif() - -if(BEMAN_EXEMPLAR_BUILD_EXAMPLES) - add_subdirectory(examples) -endif() +# Dummy content. Test that CMakeLists.txt is non-empty. \ No newline at end of file diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 898ab823..7290b0c0 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -20,7 +20,7 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): """ - Test that repositories with CMakeLists.txt pass the check. + Test that repositories with valid CMakeLists.txt. """ valid_cmake_paths = [ Path(f"{valid_prefix}/exemplar/"), @@ -37,7 +37,7 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): def test__TOPLEVEL_CMAKE__invalid(repo_info, beman_standard_check_config): """ - Test that repositories without CMakeLists.txt fail the check. + Test that repositories with invalid CMakeLists.txt. """ invalid_cmake_paths = [ Path(f"{invalid_prefix}/missing-CMAKE/"), From 687d1f15c6d0d31074e1ee2ebdf8d7b8eca05e96 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 10 Jul 2025 14:03:51 +0300 Subject: [PATCH 283/371] [beman-tidy] Added newlines for the dummy CMake files and refined the 'exclude' rule for CMake linter --- .pre-commit-config.yaml | 2 +- .../toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt | 2 +- .../beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08795ded..7a0ab0a9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: hooks: - id: gersemi name: CMake linting - exclude: ^infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/.*CMakeLists\.txt$ + exclude: ^infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.*CMakeLists\.txt$ # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt index 33ab4df8..a4d12589 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt @@ -1 +1 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. \ No newline at end of file +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt index 33ab4df8..a4d12589 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt @@ -1 +1 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. \ No newline at end of file +# Dummy content. Test that CMakeLists.txt is non-empty. From ba7ecc58fba10cd02c9afd139e18562207b619af Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 10 Jul 2025 14:10:31 +0300 Subject: [PATCH 284/371] [beman-tidy] Removed 'exclude' rule for CMake linter and added a space in the CMake file --- .pre-commit-config.yaml | 1 - .../toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7a0ab0a9..93bacb41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,6 @@ repos: hooks: - id: gersemi name: CMake linting - exclude: ^infra/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.*CMakeLists\.txt$ # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt index e69de29b..0519ecba 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt @@ -0,0 +1 @@ + \ No newline at end of file From a4663b27faa8dd4bf6f7c1019cecfbc83c23c6b4 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 10 Jul 2025 14:17:20 +0300 Subject: [PATCH 285/371] [beman-tidy] Fixed 'exclude' rule for CMake linter --- .pre-commit-config.yaml | 1 + .../toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93bacb41..e90f5b55 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: hooks: - id: gersemi name: CMake linting + exclude: ^tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists\.txt$ # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt index 0519ecba..e69de29b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt @@ -1 +0,0 @@ - \ No newline at end of file From 0e1ad8fe2859194070d4a0068c7a3f74d0a5238d Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 11 Jul 2025 00:27:04 +0300 Subject: [PATCH 286/371] [beman-tidy] Reverted changes in pre-commit config file and added .cmake-lint.yaml file to exclude CMake Linter check for particular internal test --- .pre-commit-config.yaml | 1 - .../toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e90f5b55..93bacb41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,6 @@ repos: hooks: - id: gersemi name: CMake linting - exclude: ^tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists\.txt$ # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml new file mode 100644 index 00000000..bc114417 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml @@ -0,0 +1 @@ +enabled: false From 1d9ccd82dca2cc8bb42ee36ca5355ad33366daa3 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 11 Jul 2025 16:11:50 +0300 Subject: [PATCH 287/371] [beman-tidy] Reverted changes in pre commit config file --- .pre-commit-config.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93bacb41..3c22d577 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,10 +2,10 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files - repo: https://github.com/codespell-project/codespell rev: v2.3.0 @@ -16,8 +16,9 @@ repos: - repo: https://github.com/BlankSpruce/gersemi rev: 0.15.1 hooks: - - id: gersemi - name: CMake linting + - id: gersemi + name: CMake linting + # Python linting and formatting # config file: ruff.toml (not currently present but add if needed) # https://docs.astral.sh/ruff/configuration/ From 0a25bfae2e24eacc67b16180de95c5dbb3ab2b8e Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 11 Jul 2025 19:02:54 +0300 Subject: [PATCH 288/371] [beman-tidy] Added 'exclude' rule for CMake linter to exclude test data directories --- .pre-commit-config.yaml | 1 + .../toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3c22d577..8641cfad 100644 --- a/.pre-commit-config.yaml +++ b/.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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml deleted file mode 100644 index bc114417..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/.cmake-lint.yaml +++ /dev/null @@ -1 +0,0 @@ -enabled: false From 3205ef462c5d3c24144b67b6f80c7617d559fe53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 10:18:19 +0300 Subject: [PATCH 289/371] [beman-tidy] Clean docs --- .../beman_tidy/lib/checks/beman_standard/directory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 546e1750..5eefb0b1 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -16,9 +16,9 @@ class BemanTreeDirectoryCheck(DirectoryBaseCheck): - include/beman/exemplar - src/beman/exemplar - tests/beman/exemplar - - examples/beman/exemplar - - docs/beman/exemplar - - papers/beman/exemplar + - examples/ + - docs/ + - papers/ """ def __init__(self, repo_info, beman_standard_check_config, prefix_path): From 11b5950b05d74026e3cc37858922f420da41c416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 11:12:14 +0300 Subject: [PATCH 290/371] [beman-tidy] Tweak implementation for DIRECTORY.SOURCES to be conditional --- .../beman_tidy/lib/checks/base/base_check.py | 18 ++++- .../lib/checks/beman_standard/directory.py | 19 ++++- .../beman_standard/directory/__init__.py | 0 .../beman_standard/directory/conftest.py | 16 ++++ .../src/beman/optional/exemplar.cpp | 1 + .../repo-exemplar-v2/src/beman/exemplar.cpp | 1 + .../invalid/repo-exemplar-v3/src/exemplar.cpp | 1 + .../sources/beman/exemplar/exemplar.cpp | 1 + .../source/beman/exemplar/exemplar.cpp | 1 + .../lib/beman/exemplar/exemplar.cpp | 1 + .../library/beman/exemplar/exemplar.cpp | 1 + .../src/beman/exemplar/exemplar.cpp | 1 + .../data/valid/repo-exemplar-v2/.keep | 0 .../directory/test_directory.py | 73 +++++++++++++++++++ 14 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/src/beman/optional/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/src/beman/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/src/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/sources/beman/exemplar/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/source/beman/exemplar/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/lib/beman/exemplar/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/library/beman/exemplar/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/src/beman/exemplar/exemplar.cpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/.keep create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py diff --git a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py index a12b4a00..13ee53ae 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py @@ -30,16 +30,28 @@ def __init__(self, repo_info, beman_standard_check_config, name=None): ) # save the check config - self.config = beman_standard_check_config[self.name] if not "INTERNAL." in self.name else None + 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"] if not "INTERNAL." in self.name else "REQUIREMENT" + 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"] if not "INTERNAL." in self.name else "" + 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" diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 5eefb0b1..637ccd91 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -47,7 +47,24 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config, "src") def check(self): - return self.pre_check() # Check if the directory exists and is not empty. + # Check if path with prefix `src/` exits. + src_path = self.repo_path / "src/" + if src_path.exists(): + # Check self.path (src/beman/$library) exists and is not empty. + return ( + self.pre_check() + ) + # Should not allow known source locations. + for prefix in ["source", "sources", "lib", "library"]: + prefix_path = self.repo_path / prefix + if prefix_path.exists(): + self.log( + f"Please move sources from {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 + + # Probably it's a header only library, we validate the current structure. + return True def fix(self): self.log( diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py new file mode 100644 index 00000000..515dc2bd --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/src/beman/optional/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/src/beman/optional/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/src/beman/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/src/beman/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/src/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/src/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/sources/beman/exemplar/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/sources/beman/exemplar/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/source/beman/exemplar/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v5/source/beman/exemplar/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/lib/beman/exemplar/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v6/lib/beman/exemplar/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/library/beman/exemplar/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/library/beman/exemplar/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/src/beman/exemplar/exemplar.cpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/src/beman/exemplar/exemplar.cpp new file mode 100644 index 00000000..fe827578 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/.keep b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/.keep new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py new file mode 100644 index 00000000..4c724c1b --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -0,0 +1,73 @@ +#!/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 ( + DirectorySourcesCheck, +) + +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): + pass From cfa3fd36506d91070c04a8f3d0c4d2d341737951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 11:22:18 +0300 Subject: [PATCH 291/371] [beman-tidy] Fix broken tests after making DIRECTORY.SOURCES to be conditional --- .../lib/checks/beman_standard/directory.py | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 637ccd91..37db5e9e 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -39,6 +39,7 @@ def __init__(self, repo_info, beman_standard_check_config, prefix_path): 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 """ @@ -46,30 +47,39 @@ class DirectorySourcesCheck(BemanTreeDirectoryCheck): 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): - # Check if path with prefix `src/` exits. - src_path = self.repo_path / "src/" - if src_path.exists(): - # Check self.path (src/beman/$library) exists and is not empty. - return ( - self.pre_check() - ) - # Should not allow known source locations. - for prefix in ["source", "sources", "lib", "library"]: - prefix_path = self.repo_path / prefix - if prefix_path.exists(): + # 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 sources from {prefix} to src/beman/{self.repo_name}. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#directorysources for more information." + 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 - # Probably it's a header only library, we validate the current structure. + # 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): - self.log( - f"Please move sources to src/beman/{self.repo_name}. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#directorysources for more information." - ) + # 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." + ) # TODO DIRECTORY.TESTS From 844b3aa5ba860ad1957a2df62339dfb99c53e9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 11:40:09 +0300 Subject: [PATCH 292/371] [beman-tidy] Fix linting issues --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py | 1 + tools/beman-tidy/beman_tidy/lib/checks/system/git.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 64b56ef5..b67905e4 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -6,6 +6,7 @@ from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check + # [README.*] checks category. # All checks in this file extend the ReadmeBaseCheck class. # diff --git a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py index 9e1bfc92..368cb6db 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/system/git.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/system/git.py @@ -12,7 +12,9 @@ class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): """ def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "INTERNAL.NO_UNSTAGED_CHANGES") + super().__init__( + repo_info, beman_standard_check_config, "INTERNAL.NO_UNSTAGED_CHANGES" + ) def check(self): """ From 326eff61db172e62f70288dbfd719bc0a9ee0fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 11:43:45 +0300 Subject: [PATCH 293/371] [beman-tidy] DIRECTORY.SOURCES. is now a REQUIREMENT --- tools/beman-tidy/beman_tidy/.beman-standard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index bfa38f50..48b0df98 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -114,7 +114,7 @@ DIRECTORY.INTERFACE_HEADERS: DIRECTORY.IMPLEMENTATION_HEADERS: - type: REQUIREMENT DIRECTORY.SOURCES: - - type: RECOMMENDATION # TODO: Why DIRECTORY.SOURCES is a RECOMMENDATION? + - type: REQUIREMENT DIRECTORY.TESTS: - type: REQUIREMENT DIRECTORY.EXAMPLES: From 0f0f772162accdaa0a045958674b0a1afd01a11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 12:16:20 +0300 Subject: [PATCH 294/371] [beman-tidy] Implement check REPOSITORY.CODEOWNERS --- .../beman-tidy/beman_tidy/.beman-standard.yml | 1 - .../lib/checks/beman_standard/general.py | 28 ++++++++- .../lib/checks/beman_standard/toplevel.py | 4 +- .../checks/beman_standard/general/__init__.py | 0 .../checks/beman_standard/general/conftest.py | 16 +++++ .../invalid/repo-exemplar-v1/.github/.keep | 0 .../data/invalid/repo-exemplar-v2/CODEOWNERS | 0 .../repo-exemplar-v3/.gihub/CODEOWNERS | 0 .../valid/repo-exemplar-v1/.github/CODEOWNERS | 1 + .../beman_standard/general/test_general.py | 62 +++++++++++++++++++ .../beman_standard/readme/test_readme.py | 9 --- 11 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v1/.github/.keep create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v2/CODEOWNERS create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/data/valid/repo-exemplar-v1/.github/CODEOWNERS create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index 47519973..3ae73a2a 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -30,7 +30,6 @@ REPOSITORY.NAME: - regex: REPOSITORY.CODEOWNERS: - type: REQUIREMENT - - default_group: "@bemanproject/core-reviewers" REPOSITORY.DISALLOW_GIT_SUBMODULES: - type: RECOMMENDATION diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py index d0847539..2ed595ce 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py @@ -1,7 +1,33 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from ..base.file_base_check import FileBaseCheck +from ..system.registry import register_beman_standard_check + +# [GENERAL.*] / [REPOSITORY.*] checks category. +# All checks in this file extend the GeneralBaseCheck class. +# +# Note: GeneralBaseCheck is not a registered check! + + # TODO LIBRARY.NAMES # TODO REPOSITORY.NAME -# TODO REPOSITORY.CODEOWNERS + + +@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." + ) + + # TODO REPOSITORY.DISALLOW_GIT_SUBMODULES diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index f4c4ad30..4120e18d 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -12,7 +12,7 @@ # 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) @@ -47,7 +47,7 @@ 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() diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py new file mode 100644 index 00000000..515dc2bd --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v1/.github/.keep b/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v1/.github/.keep new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v2/CODEOWNERS b/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v2/CODEOWNERS new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS b/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/valid/repo-exemplar-v1/.github/CODEOWNERS b/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/valid/repo-exemplar-v1/.github/CODEOWNERS new file mode 100644 index 00000000..dcd78f59 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/valid/repo-exemplar-v1/.github/CODEOWNERS @@ -0,0 +1 @@ +* @neatudarius diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py b/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py new file mode 100644 index 00000000..7cc67825 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py @@ -0,0 +1,62 @@ +#!/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.general import ( + RepositoryCodeownersCheck, +) + +test_data_prefix = "tests/lib/checks/beman_standard/general/data" +valid_prefix = f"{test_data_prefix}/valid" +invalid_prefix = f"{test_data_prefix}/invalid" + + +def test__REPOSITORY_CODEOWNERS__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid CMakeLists.txt. + """ + valid_cmake_paths = [ + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_cmake_paths, + RepositoryCodeownersCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__REPOSITORY_CODEOWNERS__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid CMakeLists.txt. + """ + invalid_cmake_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_cmake_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): + pass diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index 87df91ee..d660cb77 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -125,9 +125,6 @@ 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): - """ - Test that the fix method corrects an invalid README.md badges. - """ pass @@ -174,9 +171,6 @@ def test__README_IMPLEMENTS__invalid(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" - """ pass @@ -222,7 +216,4 @@ 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): - """ - Test that the fix method corrects an invalid README.md library status. - """ pass From a8922aeec82c05a865d13e966e3cf8d1bb3fac95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 13 Jul 2025 12:26:44 +0300 Subject: [PATCH 295/371] [beman-tidy] More cleanup for TOPLEVEL.CMAKE --- .../lib/checks/beman_standard/toplevel.py | 15 +++++++++------ .../CMakeLists.txt | 0 .../{invalid-CMAKE1 => repo-exemplar-v1}/LICENSE | 0 .../README.md | 0 .../{invalid-CMAKE2 => repo-exemplar-v2}/LICENSE | 0 .../README.md | 0 .../cmake/CMakeLists.txt | 0 .../{missing-CMAKE => repo-exemplar-v3}/LICENSE | 0 .../{missing-CMAKE => repo-exemplar-v3}/README.md | 0 .../{exemplar => repo-exemplar-v1}/CMakeLists.txt | 0 .../valid/{exemplar => repo-exemplar-v1}/LICENSE | 0 .../{exemplar => repo-exemplar-v1}/README.md | 0 .../beman_standard/toplevel/test_toplevel.py | 11 +++++++---- 13 files changed, 16 insertions(+), 10 deletions(-) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{invalid-CMAKE1 => repo-exemplar-v1}/CMakeLists.txt (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{invalid-CMAKE1 => repo-exemplar-v1}/LICENSE (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{invalid-CMAKE1 => repo-exemplar-v1}/README.md (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{invalid-CMAKE2 => repo-exemplar-v2}/LICENSE (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{invalid-CMAKE2 => repo-exemplar-v2}/README.md (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{invalid-CMAKE2 => repo-exemplar-v2}/cmake/CMakeLists.txt (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{missing-CMAKE => repo-exemplar-v3}/LICENSE (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{missing-CMAKE => repo-exemplar-v3}/README.md (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/{exemplar => repo-exemplar-v1}/CMakeLists.txt (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/{exemplar => repo-exemplar-v1}/LICENSE (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/{exemplar => repo-exemplar-v1}/README.md (100%) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py index f4c4ad30..5d948580 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py @@ -18,11 +18,14 @@ 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") @@ -31,13 +34,13 @@ 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." ) @@ -47,11 +50,11 @@ 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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/CMakeLists.txt similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/CMakeLists.txt rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/CMakeLists.txt diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/LICENSE rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE1/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/LICENSE similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/LICENSE rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/README.md similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/cmake/CMakeLists.txt similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/invalid-CMAKE2/cmake/CMakeLists.txt rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/cmake/CMakeLists.txt diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/LICENSE similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/LICENSE rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/README.md similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/missing-CMAKE/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/CMakeLists.txt similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/CMakeLists.txt rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/CMakeLists.txt diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/LICENSE similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/LICENSE rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/README.md similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/exemplar/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/valid/repo-exemplar-v1/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 7290b0c0..cb695889 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -23,7 +23,7 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): Test that repositories with valid CMakeLists.txt. """ valid_cmake_paths = [ - Path(f"{valid_prefix}/exemplar/"), + Path(f"{valid_prefix}/repo-exemplar-v1/"), ] run_check_for_each_path( @@ -40,9 +40,12 @@ def test__TOPLEVEL_CMAKE__invalid(repo_info, beman_standard_check_config): Test that repositories with invalid CMakeLists.txt. """ invalid_cmake_paths = [ - Path(f"{invalid_prefix}/missing-CMAKE/"), - Path(f"{invalid_prefix}/invalid-CMAKE1/"), - Path(f"{invalid_prefix}/invalid-CMAKE2/"), + # 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( From 0330622fbf22c9de71706538e6d09ef3f6efda5e Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 15:33:09 +0300 Subject: [PATCH 296/371] [beman-tidy] Added tests for TOPLEVEL.LICENSE --- .../invalid/repo-exemplar-v4/CMakeLists.txt | 1 + .../data/invalid/repo-exemplar-v4/LICENSE | 0 .../data/invalid/repo-exemplar-v4/README.md | 1 + .../invalid/repo-exemplar-v5/CMakeLists.txt | 1 + .../data/invalid/repo-exemplar-v5/README.md | 1 + .../invalid/repo-exemplar-v5/license/LICENSE | 1 + .../invalid/repo-exemplar-v6/CMakeLists.txt | 1 + .../data/invalid/repo-exemplar-v6/README.md | 1 + .../beman_standard/toplevel/test_toplevel.py | 45 +++++++++++++++++++ 9 files changed, 52 insertions(+) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt new file mode 100644 index 00000000..a4d12589 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/LICENSE new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt new file mode 100644 index 00000000..a4d12589 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt new file mode 100644 index 00000000..a4d12589 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index cb695889..449bf39b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -11,6 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.toplevel import ( ToplevelCmakeCheck, + ToplevelLicenseCheck ) test_data_prefix = "tests/lib/checks/beman_standard/toplevel/data" @@ -60,3 +61,47 @@ def test__TOPLEVEL_CMAKE__invalid(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. + """ + valid_cmake_paths = [ + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_cmake_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. + """ + invalid_cmake_paths = [ + # exemplar/ repo with empty LICENSE file. + Path(f"{invalid_prefix}/repo-exemplar-v4/"), + # exemplar/ repo with LICENSE in non-root location. + Path(f"{invalid_prefix}/repo-exemplar-v5/"), + # exemplar/ repo without LICENSE file. + Path(f"{invalid_prefix}/repo-exemplar-v6/"), + ] + + run_check_for_each_path( + False, + invalid_cmake_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 From 0f5c90bd580345879cc180bd9708460dd7cc25cd Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 15:38:57 +0300 Subject: [PATCH 297/371] [beman-tidy] Run linter and added clearer comments --- .../lib/checks/beman_standard/toplevel/test_toplevel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 449bf39b..5e07ecd2 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -11,7 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.toplevel import ( ToplevelCmakeCheck, - ToplevelLicenseCheck + ToplevelLicenseCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/toplevel/data" @@ -65,7 +65,7 @@ def test__TOPLEVEL_CMAKE__fix_inplace(repo_info, beman_standard_check_config): def test__TOPLEVEL_LICENSE__valid(repo_info, beman_standard_check_config): """ - Test that repositories with valid LICENSE. + Test that repositories with valid LICENSE pass the check. """ valid_cmake_paths = [ Path(f"{valid_prefix}/repo-exemplar-v1/"), @@ -82,7 +82,7 @@ def test__TOPLEVEL_LICENSE__valid(repo_info, beman_standard_check_config): def test__TOPLEVEL_LICENSE__invalid(repo_info, beman_standard_check_config): """ - Test that repositories with invalid LICENSE. + Test that repositories with invalid LICENSE fail the check. """ invalid_cmake_paths = [ # exemplar/ repo with empty LICENSE file. From 2aa51cc86cd137b869138cd1db03eabb8aea2d5f Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 15:49:51 +0300 Subject: [PATCH 298/371] [beman-tidy] Added tests for TOPLEVEL.README --- .../invalid/repo-exemplar-v7/CMakeLists.txt | 1 + .../data/invalid/repo-exemplar-v7/LICENSE | 1 + .../data/invalid/repo-exemplar-v7/README.md | 0 .../invalid/repo-exemplar-v8/CMakeLists.txt | 1 + .../data/invalid/repo-exemplar-v8/LICENSE | 1 + .../invalid/repo-exemplar-v8/readme/README.md | 1 + .../invalid/repo-exemplar-v9/CMakeLists.txt | 1 + .../data/invalid/repo-exemplar-v9/LICENSE | 1 + .../beman_standard/toplevel/test_toplevel.py | 45 +++++++++++++++++++ 9 files changed, 52 insertions(+) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt new file mode 100644 index 00000000..a4d12589 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/README.md new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt new file mode 100644 index 00000000..a4d12589 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md new file mode 100644 index 00000000..19e661f0 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md @@ -0,0 +1 @@ +Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt new file mode 100644 index 00000000..a4d12589 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt @@ -0,0 +1 @@ +# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE @@ -0,0 +1 @@ +Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 5e07ecd2..6da8289d 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -12,6 +12,7 @@ from beman_tidy.lib.checks.beman_standard.toplevel import ( ToplevelCmakeCheck, ToplevelLicenseCheck, + ToplevelReadmeCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/toplevel/data" @@ -105,3 +106,47 @@ def test__TOPLEVEL_LICENSE__invalid(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_cmake_paths = [ + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_cmake_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_cmake_paths = [ + # exemplar/ repo with empty README.md file. + Path(f"{invalid_prefix}/repo-exemplar-v7/"), + # exemplar/ repo with README.md in non-root location. + Path(f"{invalid_prefix}/repo-exemplar-v8/"), + # exemplar/ repo without README.md file. + Path(f"{invalid_prefix}/repo-exemplar-v9/"), + ] + + run_check_for_each_path( + False, + invalid_cmake_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 From 2f538599ae839ba789ef759952af9729e937f96c Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 15:56:48 +0300 Subject: [PATCH 299/371] [beman-tidy] Added clearer comments for CMakeLists.txt checks --- .../tests/lib/checks/beman_standard/toplevel/test_toplevel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index cb695889..31b96f4f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -20,7 +20,7 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): """ - Test that repositories with valid CMakeLists.txt. + Test that repositories with valid CMakeLists.txt pass the check. """ valid_cmake_paths = [ Path(f"{valid_prefix}/repo-exemplar-v1/"), @@ -37,7 +37,7 @@ def test__TOPLEVEL_CMAKE__valid(repo_info, beman_standard_check_config): def test__TOPLEVEL_CMAKE__invalid(repo_info, beman_standard_check_config): """ - Test that repositories with invalid CMakeLists.txt. + Test that repositories with invalid CMakeLists.txt fail the check. """ invalid_cmake_paths = [ # exemplar/ repo with empty CMakeLists.txt file. From 37d7f04cfcd3329305e85287ca3769d95c3e3e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 14 Jul 2025 16:15:01 +0300 Subject: [PATCH 300/371] [beman-tidy] Move REPOSITORY.CODEOWNERS to repository.py --- .../lib/checks/beman_standard/general.py | 24 +------------- .../lib/checks/beman_standard/repository.py | 32 +++++++++++++++++++ tools/beman-tidy/beman_tidy/lib/pipeline.py | 1 + .../{general => repository}/__init__.py | 0 .../{general => repository}/conftest.py | 0 .../invalid/repo-exemplar-v1/.github/.keep | 0 .../data/invalid/repo-exemplar-v2/CODEOWNERS | 0 .../repo-exemplar-v3/.gihub/CODEOWNERS | 0 .../valid/repo-exemplar-v1/.github/CODEOWNERS | 0 .../test_repository.py} | 4 +-- 10 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py rename tools/beman-tidy/tests/lib/checks/beman_standard/{general => repository}/__init__.py (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/{general => repository}/conftest.py (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/{general => repository}/data/invalid/repo-exemplar-v1/.github/.keep (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/{general => repository}/data/invalid/repo-exemplar-v2/CODEOWNERS (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/{general => repository}/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/{general => repository}/data/valid/repo-exemplar-v1/.github/CODEOWNERS (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/{general/test_general.py => repository/test_repository.py} (92%) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py index 2ed595ce..1071aa89 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py @@ -1,33 +1,11 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from ..base.file_base_check import FileBaseCheck -from ..system.registry import register_beman_standard_check -# [GENERAL.*] / [REPOSITORY.*] checks category. +# [GENERAL.*] checks category. # All checks in this file extend the GeneralBaseCheck class. # # Note: GeneralBaseCheck is not a registered check! # TODO LIBRARY.NAMES -# TODO REPOSITORY.NAME - - -@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." - ) - - -# TODO REPOSITORY.DISALLOW_GIT_SUBMODULES diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py new file mode 100644 index 00000000..cb65e425 --- /dev/null +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +from ..base.file_base_check import FileBaseCheck +from ..system.registry import register_beman_standard_check + +# [REPOSITORY.*] checks category. +# All checks in this file extend the FileBaseCheck class. +# +# Note: FileBaseCheck is not a registered check! + + +# TODO REPOSITORY.NAME + + +@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." + ) + + +# TODO REPOSITORY.DISALLOW_GIT_SUBMODULES diff --git a/tools/beman-tidy/beman_tidy/lib/pipeline.py b/tools/beman-tidy/beman_tidy/lib/pipeline.py index a5d7d408..fadd1198 100644 --- a/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ b/tools/beman-tidy/beman_tidy/lib/pipeline.py @@ -16,6 +16,7 @@ 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" diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/__init__.py similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/__init__.py rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/__init__.py diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/conftest.py similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/conftest.py rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/conftest.py diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v1/.github/.keep b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.github/.keep similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v1/.github/.keep rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.github/.keep diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v2/CODEOWNERS b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/CODEOWNERS similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v2/CODEOWNERS rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/CODEOWNERS diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gihub/CODEOWNERS diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/data/valid/repo-exemplar-v1/.github/CODEOWNERS b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v1/.github/CODEOWNERS similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/data/valid/repo-exemplar-v1/.github/CODEOWNERS rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v1/.github/CODEOWNERS diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py similarity index 92% rename from tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py rename to tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 7cc67825..f08062bb 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/general/test_general.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -9,11 +9,11 @@ ) # Actual tested checks. -from beman_tidy.lib.checks.beman_standard.general import ( +from beman_tidy.lib.checks.beman_standard.repository import ( RepositoryCodeownersCheck, ) -test_data_prefix = "tests/lib/checks/beman_standard/general/data" +test_data_prefix = "tests/lib/checks/beman_standard/repository/data" valid_prefix = f"{test_data_prefix}/valid" invalid_prefix = f"{test_data_prefix}/invalid" From 9425e01cae43cbc849a59ce31ccd1ec957b68a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 14 Jul 2025 16:36:27 +0300 Subject: [PATCH 301/371] [beman-tidy] Move REPOSITORY.CODEOWNERS to repository.py --- .../lib/checks/beman_standard/repository/test_repository.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index f08062bb..ff605d64 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -20,7 +20,7 @@ def test__REPOSITORY_CODEOWNERS__valid(repo_info, beman_standard_check_config): """ - Test that repositories with valid CMakeLists.txt. + Test that repositories with valid CODEOWNERS pass the check. """ valid_cmake_paths = [ Path(f"{valid_prefix}/repo-exemplar-v1/"), @@ -37,7 +37,7 @@ def test__REPOSITORY_CODEOWNERS__valid(repo_info, beman_standard_check_config): def test__REPOSITORY_CODEOWNERS__invalid(repo_info, beman_standard_check_config): """ - Test that repositories with invalid CMakeLists.txt. + Test that repositories with invalid CODEOWNERS fail the check. """ invalid_cmake_paths = [ # exemplar/ repo without CODEOWNERS file inside .github/. From 788277cb8e0806c8ba9769310b9e256503a60d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Mon, 14 Jul 2025 16:41:08 +0300 Subject: [PATCH 302/371] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 856bd532..4ff90a43 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @ednolan @neatudarius @rishyak @wusatosi +* @ednolan @neatudarius @rishyak @wusatosi @JeffGarland From 66094a075b86ab2476f25238045e19d02eb155e5 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 16:41:24 +0300 Subject: [PATCH 303/371] [beman-tidy] Simplify test cases for LICENSE checks --- .../toplevel/data/invalid/repo-exemplar-v1/LICENSE | 1 - .../data/invalid/repo-exemplar-v2/{ => license}/LICENSE | 0 .../toplevel/data/invalid/repo-exemplar-v3/LICENSE | 1 - .../toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt | 1 - .../toplevel/data/invalid/repo-exemplar-v4/LICENSE | 0 .../toplevel/data/invalid/repo-exemplar-v4/README.md | 1 - .../toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt | 1 - .../toplevel/data/invalid/repo-exemplar-v5/README.md | 1 - .../toplevel/data/invalid/repo-exemplar-v5/license/LICENSE | 1 - .../toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt | 1 - .../toplevel/data/invalid/repo-exemplar-v6/README.md | 1 - .../lib/checks/beman_standard/toplevel/test_toplevel.py | 6 +++--- 12 files changed, 3 insertions(+), 12 deletions(-) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/{ => license}/LICENSE (100%) delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE index e4fa6a84..e69de29b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/LICENSE @@ -1 +0,0 @@ -Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/license/LICENSE similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/LICENSE rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/license/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/LICENSE deleted file mode 100644 index e4fa6a84..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt deleted file mode 100644 index a4d12589..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/LICENSE deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md deleted file mode 100644 index 19e661f0..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v4/README.md +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt deleted file mode 100644 index a4d12589..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md deleted file mode 100644 index 19e661f0..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/README.md +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE deleted file mode 100644 index e4fa6a84..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v5/license/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt deleted file mode 100644 index a4d12589..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md deleted file mode 100644 index 19e661f0..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v6/README.md +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 4f2c7b4d..d72db99f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -86,11 +86,11 @@ def test__TOPLEVEL_LICENSE__invalid(repo_info, beman_standard_check_config): """ invalid_cmake_paths = [ # exemplar/ repo with empty LICENSE file. - Path(f"{invalid_prefix}/repo-exemplar-v4/"), + Path(f"{invalid_prefix}/repo-exemplar-v1/"), # exemplar/ repo with LICENSE in non-root location. - Path(f"{invalid_prefix}/repo-exemplar-v5/"), + Path(f"{invalid_prefix}/repo-exemplar-v2/"), # exemplar/ repo without LICENSE file. - Path(f"{invalid_prefix}/repo-exemplar-v6/"), + Path(f"{invalid_prefix}/repo-exemplar-v3/"), ] run_check_for_each_path( From 8c56c92c208f9d2ce14870498a2253415dd122cb Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 16:46:40 +0300 Subject: [PATCH 304/371] [beman-tidy] Clean up comments and repaired wrong path names --- .../checks/beman_standard/toplevel/test_toplevel.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index d72db99f..64182d8b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -24,6 +24,7 @@ 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 non-empty CMakeLists.txt file. Path(f"{valid_prefix}/repo-exemplar-v1/"), ] @@ -67,13 +68,14 @@ def test__TOPLEVEL_LICENSE__valid(repo_info, beman_standard_check_config): """ Test that repositories with valid LICENSE pass the check. """ - valid_cmake_paths = [ + valid_license_paths = [ + # exemplar/ repo with non-empty LICENSE file. Path(f"{valid_prefix}/repo-exemplar-v1/"), ] run_check_for_each_path( True, - valid_cmake_paths, + valid_license_paths, ToplevelLicenseCheck, repo_info, beman_standard_check_config, @@ -84,7 +86,7 @@ def test__TOPLEVEL_LICENSE__invalid(repo_info, beman_standard_check_config): """ Test that repositories with invalid LICENSE fail the check. """ - invalid_cmake_paths = [ + invalid_license_paths = [ # exemplar/ repo with empty LICENSE file. Path(f"{invalid_prefix}/repo-exemplar-v1/"), # exemplar/ repo with LICENSE in non-root location. @@ -95,7 +97,7 @@ def test__TOPLEVEL_LICENSE__invalid(repo_info, beman_standard_check_config): run_check_for_each_path( False, - invalid_cmake_paths, + invalid_license_paths, ToplevelLicenseCheck, repo_info, beman_standard_check_config, From a483ef80abe3634b3c1824aef280310d48e8546f Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 16:48:59 +0300 Subject: [PATCH 305/371] [beman-tidy] Clearer comments --- .../tests/lib/checks/beman_standard/toplevel/test_toplevel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 64182d8b..d3877e0c 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -24,7 +24,7 @@ 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 non-empty CMakeLists.txt file. + # exemplar/ repo with valid CMakeLists.txt file. Path(f"{valid_prefix}/repo-exemplar-v1/"), ] @@ -69,7 +69,7 @@ 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 non-empty LICENSE file. + # exemplar/ repo with valid LICENSE file. Path(f"{valid_prefix}/repo-exemplar-v1/"), ] From e2c27225eff420c1f40cfa7f65ca20a6e378a7ad Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 16:55:19 +0300 Subject: [PATCH 306/371] [beman-tidy] Update tests and update test paths for README.md checks --- .../data/invalid/repo-exemplar-v1/README.md | 1 - .../repo-exemplar-v2/{ => readme}/README.md | 0 .../README.md => repo-exemplar-v3/.keep} | 0 .../data/invalid/repo-exemplar-v3/README.md | 1 - .../data/invalid/repo-exemplar-v7/CMakeLists.txt | 1 - .../data/invalid/repo-exemplar-v7/LICENSE | 1 - .../data/invalid/repo-exemplar-v8/CMakeLists.txt | 1 - .../data/invalid/repo-exemplar-v8/LICENSE | 1 - .../invalid/repo-exemplar-v8/readme/README.md | 1 - .../data/invalid/repo-exemplar-v9/CMakeLists.txt | 1 - .../data/invalid/repo-exemplar-v9/LICENSE | 1 - .../beman_standard/toplevel/test_toplevel.py | 15 ++++++++------- 12 files changed, 8 insertions(+), 16 deletions(-) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/{ => readme}/README.md (100%) rename tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/{repo-exemplar-v7/README.md => repo-exemplar-v3/.keep} (100%) delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md index 19e661f0..e69de29b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v1/README.md @@ -1 +0,0 @@ -Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/readme/README.md similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/readme/README.md diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/README.md deleted file mode 100644 index 19e661f0..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/README.md +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt deleted file mode 100644 index a4d12589..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE deleted file mode 100644 index e4fa6a84..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v7/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt deleted file mode 100644 index a4d12589..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE deleted file mode 100644 index e4fa6a84..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md deleted file mode 100644 index 19e661f0..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v8/readme/README.md +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that README.md is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt deleted file mode 100644 index a4d12589..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -# Dummy content. Test that CMakeLists.txt is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE deleted file mode 100644 index e4fa6a84..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v9/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Dummy content. Test that LICENSE is non-empty. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py index 0c722df6..9fdeac5e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/test_toplevel.py @@ -114,13 +114,14 @@ def test__TOPLEVEL_README__valid(repo_info, beman_standard_check_config): """ Test that repositories with valid README.md pass the check. """ - valid_cmake_paths = [ + valid_readme_paths = [ + # exemplar/ repo with valid README.md file. Path(f"{valid_prefix}/repo-exemplar-v1/"), ] run_check_for_each_path( True, - valid_cmake_paths, + valid_readme_paths, ToplevelReadmeCheck, repo_info, beman_standard_check_config, @@ -131,18 +132,18 @@ def test__TOPLEVEL_README__invalid(repo_info, beman_standard_check_config): """ Test that repositories with invalid README.md fail the check. """ - invalid_cmake_paths = [ + invalid_readme_paths = [ # exemplar/ repo with empty README.md file. - Path(f"{invalid_prefix}/repo-exemplar-v7/"), + Path(f"{invalid_prefix}/repo-exemplar-v1/"), # exemplar/ repo with README.md in non-root location. - Path(f"{invalid_prefix}/repo-exemplar-v8/"), + Path(f"{invalid_prefix}/repo-exemplar-v2/"), # exemplar/ repo without README.md file. - Path(f"{invalid_prefix}/repo-exemplar-v9/"), + Path(f"{invalid_prefix}/repo-exemplar-v3/"), ] run_check_for_each_path( False, - invalid_cmake_paths, + invalid_readme_paths, ToplevelReadmeCheck, repo_info, beman_standard_check_config, From f8d426e901d80fd14c58ad7b9ae9dae6789043ff Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 18:35:06 +0300 Subject: [PATCH 307/371] [beman-tidy] Implement check() for repository default branch --- .../beman-tidy/beman_tidy/.beman-standard.yml | 2 ++ .../lib/checks/beman_standard/repository.py | 21 +++++++++++++++++++ tools/beman-tidy/beman_tidy/lib/utils/git.py | 4 ++++ 3 files changed, 27 insertions(+) diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index 3ae73a2a..e3c95e3c 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -30,6 +30,8 @@ REPOSITORY.NAME: - regex: REPOSITORY.CODEOWNERS: - type: REQUIREMENT +REPOSITORY.DEFAULT_BRANCH: + - type: REQUIREMENT REPOSITORY.DISALLOW_GIT_SUBMODULES: - type: RECOMMENDATION diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index cb65e425..e4c1ce68 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.file_base_check import FileBaseCheck +from ..base.base_check import BaseCheck from ..system.registry import register_beman_standard_check # [REPOSITORY.*] checks category. @@ -29,4 +30,24 @@ def fix(self): ) +@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): + if self.repo_info["default_branch"] == "main": + return True + + self.log( + f"The default branch of the repository should be 'main', but it is '{self.repo_info['default_branch']}'." + ) + return False + + def fix(self): + self.log( + "Please change the default branch to 'main'. This typically needs to be done through your Git hosting platform (GitHub, GitLab, etc.)." + ) + + # TODO REPOSITORY.DISALLOW_GIT_SUBMODULES diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index 7f8e3d85..cb0cb416 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -33,6 +33,9 @@ def get_repo_info(path: str): # Get the current branch current_branch = repo.active_branch.name + # Get the default branch + default_branch = repo.git.symbolic_ref("refs/remotes/origin/HEAD").split("/")[-1] + # Get the commit hash commit_hash = repo.head.commit.hexsha @@ -47,6 +50,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, From 63dacded7d4f9e462792513a9f67aced935b698a Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 18:35:40 +0300 Subject: [PATCH 308/371] [beman-tidy] Added tests for repository default branch --- .../repository/test_repository.py | 53 +++++++++++++++++-- tools/beman-tidy/tests/utils/conftest.py | 1 + tools/beman-tidy/tests/utils/path_runners.py | 27 ++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index ff605d64..659d0137 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -6,11 +6,13 @@ 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 ( RepositoryCodeownersCheck, + RepositoryDefaultBranchCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/repository/data" @@ -22,13 +24,14 @@ def test__REPOSITORY_CODEOWNERS__valid(repo_info, beman_standard_check_config): """ Test that repositories with valid CODEOWNERS pass the check. """ - valid_cmake_paths = [ + valid_codeowners_paths = [ + # exemplar/ repo with valid .github/CODEOWNERS file. Path(f"{valid_prefix}/repo-exemplar-v1/"), ] run_check_for_each_path( True, - valid_cmake_paths, + valid_codeowners_paths, RepositoryCodeownersCheck, repo_info, beman_standard_check_config, @@ -39,7 +42,7 @@ def test__REPOSITORY_CODEOWNERS__invalid(repo_info, beman_standard_check_config) """ Test that repositories with invalid CODEOWNERS fail the check. """ - invalid_cmake_paths = [ + invalid_codeowners_paths = [ # exemplar/ repo without CODEOWNERS file inside .github/. Path(f"{invalid_prefix}/repo-exemplar-v1/"), # exemplar/ repo with CODEOWNERS in root. @@ -50,7 +53,7 @@ def test__REPOSITORY_CODEOWNERS__invalid(repo_info, beman_standard_check_config) run_check_for_each_path( False, - invalid_cmake_paths, + invalid_codeowners_paths, RepositoryCodeownersCheck, repo_info, beman_standard_check_config, @@ -60,3 +63,45 @@ def test__REPOSITORY_CODEOWNERS__invalid(repo_info, beman_standard_check_config) @pytest.mark.skip(reason="NOT implemented") def test__REPOSITORY_CODEOWNERS__fix_inplace(repo_info, beman_standard_check_config): 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"}, + ] + + 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): + pass diff --git a/tools/beman-tidy/tests/utils/conftest.py b/tools/beman-tidy/tests/utils/conftest.py index 71d82c06..99b6ed40 100644 --- a/tools/beman-tidy/tests/utils/conftest.py +++ b/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/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 746eee11..64535d60 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/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 ): From af5954133d136ce2cf30872cdf1cc944b9b10faf Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 19:02:46 +0300 Subject: [PATCH 309/371] [beman-tidy] Run linter Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../lib/checks/beman_standard/repository/test_repository.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 659d0137..2a9ea8d7 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -103,5 +103,7 @@ def test__REPOSITORY_DEFAULT_BRANCH__invalid(repo_info, beman_standard_check_con @pytest.mark.skip(reason="NOT implemented") -def test__REPOSITORY_DEFAULT_BRANCH__fix_inplace(repo_info, beman_standard_check_config): +def test__REPOSITORY_DEFAULT_BRANCH__fix_inplace( + repo_info, beman_standard_check_config +): pass From f4fc90806cc9dd324490ea89aebc935f93dfe6c8 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 19:26:21 +0300 Subject: [PATCH 310/371] [beman-tidy] Simplify check, correct 'fix' log, run linter --- .../lib/checks/beman_standard/repository.py | 15 ++++++++------- tools/beman-tidy/beman_tidy/lib/utils/git.py | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index e4c1ce68..4ce6a294 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -36,17 +36,18 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - if self.repo_info["default_branch"] == "main": - return True + 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 - self.log( - f"The default branch of the repository should be 'main', but it is '{self.repo_info['default_branch']}'." - ) - return False + return True def fix(self): self.log( - "Please change the default branch to 'main'. This typically needs to be done through your Git hosting platform (GitHub, GitLab, etc.)." + "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." ) diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index cb0cb416..a3410c01 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -34,7 +34,8 @@ def get_repo_info(path: str): current_branch = repo.active_branch.name # Get the default branch - default_branch = repo.git.symbolic_ref("refs/remotes/origin/HEAD").split("/")[-1] + 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 From cc0f367d3aaca36737011eb2eb1631e02c349df5 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 19:32:48 +0300 Subject: [PATCH 311/371] [beman-tidy] Run linter --- .../beman_tidy/lib/checks/beman_standard/repository.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index 4ce6a294..6745dbe8 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -38,10 +38,8 @@ def __init__(self, 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 + self.log(f"Invalid default branch in repo: {default_branch} vs 'main'.") + return False return True From ed5b48dd5a001ceb72406428c4f94805d32e4094 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 21:10:13 +0300 Subject: [PATCH 312/371] [beman-tidy] Added more invalid tests --- .../checks/beman_standard/repository/test_repository.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 2a9ea8d7..ec1551d8 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -92,6 +92,14 @@ def test__REPOSITORY_DEFAULT_BRANCH__invalid(repo_info, beman_standard_check_con repo_info.copy() | {"default_branch": "develop"}, repo_info.copy() | {"default_branch": "dev"}, repo_info.copy() | {"default_branch": "trunk"}, + repo_info.copy() | {"default_branch": "tdefault"}, + 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( From cc69aa870ec6dfae3e8e5510e302a38ebb4400b4 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 14 Jul 2025 21:19:21 +0300 Subject: [PATCH 313/371] [beman-tidy] Fixed typo :) --- .../lib/checks/beman_standard/repository/test_repository.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index ec1551d8..c26989df 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -92,7 +92,7 @@ def test__REPOSITORY_DEFAULT_BRANCH__invalid(repo_info, beman_standard_check_con repo_info.copy() | {"default_branch": "develop"}, repo_info.copy() | {"default_branch": "dev"}, repo_info.copy() | {"default_branch": "trunk"}, - repo_info.copy() | {"default_branch": "tdefault"}, + repo_info.copy() | {"default_branch": "default"}, repo_info.copy() | {"default_branch": "production"}, repo_info.copy() | {"default_branch": "release"}, repo_info.copy() | {"default_branch": "stable"}, From 819668344c6d493f96f51dfd902a323d28964316 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 15 Jul 2025 16:29:28 +0300 Subject: [PATCH 314/371] [beman-tidy] Implement DIRECTORY.INTERFACE_HEADERS check and add tests --- .../lib/checks/beman_standard/directory.py | 47 +++++++++++++- .../beman_standard/directory/__init__.py | 0 .../beman_standard/directory/conftest.py | 16 +++++ .../invalid/repo-exemplar-v3/identity.hpp | 0 .../beman/repo-exemplar-v3/identity.hpp | 0 .../beman/repo-exemplar-v1/identity.hpp | 0 .../directory/test_directory.py | 62 +++++++++++++++++++ tools/beman-tidy/tests/utils/path_runners.py | 2 + 8 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/beman/repo-exemplar-v3/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/repo-exemplar-v1/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index d533bb3a..e67aa039 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import os from ..base.directory_base_check import DirectoryBaseCheck from ..system.registry import register_beman_standard_check @@ -19,7 +20,51 @@ def __init__(self, repo_info, beman_standard_check_config, prefix_path): ) -# TODO DIRECTORY.INTERFACE_HEADERS +@register_beman_standard_check("DIRECTORY.INTERFACE_HEADERS") +class DirectoryInterfaceHeadersCheck(DirectoryBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config, ".") + + def check(self): + """ + Check that all public header files reside within the include/beman// directory. + """ + # Check if the path exists. + # Example path: "exemplar/include/beman/exemplar" + include_path = self.path / "include" / "beman" / self.repo_info["name"] + if not os.path.exists(include_path) or os.path.isfile(include_path) or len(os.listdir(include_path)) == 0: + self.log( + f"The path '{self.path}' does not exist, is a file or is empty." + " All public header files must reside within include/beman//." + ) + return False + + # Get all .hpp files paths, excluding certain directories. + exclude_dirs = {'src'} + if self.repo_info["name"] == "exemplar": + exclude_dirs.add('cookiecutter') + + hpp_files = [] + for root, dirs, files in os.walk(self.path): + dirs[:] = [d for d in dirs if d not in exclude_dirs] + + for name in files: + if name.lower().endswith('.hpp'): + hpp_files.append(os.path.join(root, name)) + + # Check that all .hpp files are under the include/beman// + for hpp_file in hpp_files: + if not hpp_file.startswith(str(include_path)): + self.log( + f"Header file '{hpp_file}' is not under include/beman/{self.repo_info['name']}/ directory." + " All public header files must reside within include/beman//." + ) + return False + + return True + + def fix(self): + pass # TODO DIRECTORY.IMPLEMENTATION_HEADERS diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/conftest.py new file mode 100644 index 00000000..515dc2bd --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/identity.hpp new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/beman/repo-exemplar-v3/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/beman/repo-exemplar-v3/identity.hpp new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/repo-exemplar-v1/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/repo-exemplar-v1/identity.hpp new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py new file mode 100644 index 00000000..1113dcc2 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -0,0 +1,62 @@ +#!/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 ( + DirectoryInterfaceHeadersCheck, +) + +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_INTERFACE_HEADERS__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with valid public header files pass the check. + """ + valid_headers_paths = [ + # exemplar/ repo with valid public headers. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_headers_paths, + DirectoryInterfaceHeadersCheck, + repo_info, + beman_standard_check_config, + ) + +def test__DIRECTORY_INTERFACE_HEADERS__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with invalid public header files fail the check. + """ + invalid_headers_paths = [ + # exemplar/ repo without include/beman// directory. + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with include/beman// directory but no public headers. + Path(f"{invalid_prefix}/repo-exemplar-v2/"), + # exemplar/ repo with public headers outside include/beman// directory. + Path(f"{invalid_prefix}/repo-exemplar-v3/"), + ] + + run_check_for_each_path( + False, + invalid_headers_paths, + DirectoryInterfaceHeadersCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="NOT implemented") +def test__DIRECTORY_INTERFACE_HEADERS__fix_inplace(repo_info, beman_standard_check_config): + pass diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 64535d60..4f0923a7 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -52,6 +52,8 @@ def run_check_for_each_path( if os.path.isdir(path): # For repo checks, modify the repo_info to point to the test directory repo_info["top_level"] = Path(path) + # Set the last part of the path as the repository name + repo_info["name"] = path.parts[-1] check_instance = check_class(repo_info, beman_standard_check_config) From 5ae14e1f2f33baa0489b1e5bd47e3e87f0c627fa Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 15 Jul 2025 16:33:22 +0300 Subject: [PATCH 315/371] [beman-tidy] Run linter Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../beman_tidy/lib/checks/beman_standard/directory.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index e67aa039..52c33117 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -32,7 +32,11 @@ def check(self): # Check if the path exists. # Example path: "exemplar/include/beman/exemplar" include_path = self.path / "include" / "beman" / self.repo_info["name"] - if not os.path.exists(include_path) or os.path.isfile(include_path) or len(os.listdir(include_path)) == 0: + if ( + not os.path.exists(include_path) + or os.path.isfile(include_path) + or len(os.listdir(include_path)) == 0 + ): self.log( f"The path '{self.path}' does not exist, is a file or is empty." " All public header files must reside within include/beman//." From 4fb32e34df2376dee187bf74d5bba12dcd2b9552 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 15 Jul 2025 16:36:05 +0300 Subject: [PATCH 316/371] [beman-tidy] Run linter --- .../beman_tidy/lib/checks/beman_standard/directory.py | 6 +++--- .../lib/checks/beman_standard/directory/test_directory.py | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 52c33117..e3b32d01 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -44,16 +44,16 @@ def check(self): return False # Get all .hpp files paths, excluding certain directories. - exclude_dirs = {'src'} + exclude_dirs = {"src"} if self.repo_info["name"] == "exemplar": - exclude_dirs.add('cookiecutter') + exclude_dirs.add("cookiecutter") hpp_files = [] for root, dirs, files in os.walk(self.path): dirs[:] = [d for d in dirs if d not in exclude_dirs] for name in files: - if name.lower().endswith('.hpp'): + if name.lower().endswith(".hpp"): hpp_files.append(os.path.join(root, name)) # Check that all .hpp files are under the include/beman// diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py index 1113dcc2..c844727d 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -35,6 +35,7 @@ def test__DIRECTORY_INTERFACE_HEADERS__valid(repo_info, beman_standard_check_con beman_standard_check_config, ) + def test__DIRECTORY_INTERFACE_HEADERS__invalid(repo_info, beman_standard_check_config): """ Test that repositories with invalid public header files fail the check. @@ -58,5 +59,7 @@ def test__DIRECTORY_INTERFACE_HEADERS__invalid(repo_info, beman_standard_check_c @pytest.mark.skip(reason="NOT implemented") -def test__DIRECTORY_INTERFACE_HEADERS__fix_inplace(repo_info, beman_standard_check_config): +def test__DIRECTORY_INTERFACE_HEADERS__fix_inplace( + repo_info, beman_standard_check_config +): pass From a21248cf407a3e44a84cfb145a033be88642cc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 15 Jul 2025 19:32:32 +0300 Subject: [PATCH 317/371] [beman-tidy] Improve docs --- .../beman_tidy/lib/checks/beman_standard/directory.py | 11 ++++++----- .../data/invalid/repo-exemplar-v2/bla/LICENSE | 1 + .../toplevel/data/invalid/repo-exemplar-v3/.keep | 0 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/bla/LICENSE create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 37db5e9e..d32772d9 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -11,14 +11,15 @@ # Note: DirectoryBaseCheck is not a registered check! class BemanTreeDirectoryCheck(DirectoryBaseCheck): """ - Check if the directory tree is a Beman tree: ${prefix_path}/beman/${short_name}. + Beman tree: ${prefix_path}/beman/${short_name}. + Available via member: self.path + Examples for a repo named "exemplar": - include/beman/exemplar - - src/beman/exemplar - tests/beman/exemplar - - examples/ - - docs/ - - papers/ + - 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): diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/bla/LICENSE b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v2/bla/LICENSE new file mode 100644 index 00000000..e4fa6a84 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep b/tools/beman-tidy/tests/lib/checks/beman_standard/toplevel/data/invalid/repo-exemplar-v3/.keep new file mode 100644 index 00000000..e69de29b From ade1992cba30446f9969d36ab616cf856da0e783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 15 Jul 2025 19:34:24 +0300 Subject: [PATCH 318/371] [beman-tidy] Add todo --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index d32772d9..fc47c55e 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -54,6 +54,7 @@ def pre_check(self): 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: From aa24c86bf30c22ef101a82abf407f22f3ce1eec7 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 16 Jul 2025 16:01:05 +0300 Subject: [PATCH 319/371] [beman-tidy] Added check and tests for LICENSE.APPROVED --- .../lib/checks/beman_standard/license.py | 32 +- .../checks/beman_standard/license/__init__.py | 0 .../checks/beman_standard/license/conftest.py | 16 + .../license/data/invalid/invalid-LICENSE-v1 | 220 ++++++++++++++ .../license/data/invalid/invalid-LICENSE-v2 | 56 ++++ .../license/data/invalid/invalid-LICENSE-v3 | 24 ++ .../license/data/valid/LICENSE-v1 | 278 ++++++++++++++++++ .../license/data/valid/LICENSE-v2 | 23 ++ .../license/data/valid/LICENSE-v3 | 21 ++ .../beman_standard/license/test_license.py | 68 +++++ 10 files changed, 737 insertions(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/conftest.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 6eb75ab5..c7bbb95f 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception from ..base.file_base_check import FileBaseCheck +from ..system.registry import register_beman_standard_check + # [LICENSE.*] checks category. # All checks in this file extend the LicenseBaseCheck class. @@ -14,7 +16,35 @@ 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): + lines = self.read_lines_strip() + + approved_licenses = [ + "Apache License", + "Boost Software License", + "MIT License" + ] + + for line in lines: + if any(license_name in line for license_name in approved_licenses): + return True + + self.log( + f"The file '{self.path}' does not contain an approved license. " + "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 diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/conftest.py new file mode 100644 index 00000000..515dc2bd --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 new file mode 100644 index 00000000..92530788 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 @@ -0,0 +1,220 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble +The GNU General Public License is a free, copyleft license for software and other kinds of works. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. + +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS 0. Definitions. +“This License” refers to version 3 of the GNU General Public License. + +“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + +“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. + +To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. + +A “covered work” means either the unmodified Program or a work based on the Program. + +To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + +To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + +1. Source Code. + The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. + +A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + +The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + +The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +2. Basic Permissions. + All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. + No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + +4. Conveying Verbatim Copies. + You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. + You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + +a) The work must carry prominent notices stating that you modified it, and giving a relevant date. +b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. +c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. +d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + +6. Conveying Non-Source Forms. + You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + +a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. +b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. +c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. +d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. +e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + +A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + +“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + +7. Additional Terms. + “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + +a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or +b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or +c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or +d) Limiting the use for publicity purposes of names of licensors or authors of the material; or +e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or +f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. +All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + +8. Termination. + You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + +9. Acceptance Not Required for Having Copies. + You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + +An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + +11. Patents. + A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. + +A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + +In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + +A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + +13. Use with the GNU Affero General Public License. + Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. + +14. Revised Versions of this License. + The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + +15. Disclaimer of Warranty. + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . + +The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 new file mode 100644 index 00000000..f2f81d6d --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 @@ -0,0 +1,56 @@ +GNU LESSER GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. + +0. Additional Definitions. +As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. + +“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. + +An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. + +A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. + +The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. + +The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. + +1. Exception to Section 3 of the GNU GPL. +You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. + +2. Conveying Modified Versions. +If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: + +a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or +b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. +3. Object Code Incorporating Material from Library Header Files. +The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: + +a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. +b) Accompany the object code with a copy of the GNU GPL and this license document. +4. Combined Works. +You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: + +a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. +b) Accompany the Combined Work with a copy of the GNU GPL and this license document. +c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. +d) Do one of the following: +0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. +1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. +e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) +5. Combined Libraries. +You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: + +a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. +b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. +6. Revised Versions of the GNU Lesser General Public License. +The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 new file mode 100644 index 00000000..9726d435 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 @@ -0,0 +1,24 @@ +BSD-2-Clause + +Copyright + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or other +materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 new file mode 100644 index 00000000..319395db --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 @@ -0,0 +1,278 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + 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. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM 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. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +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 +CONTRIBUTORS 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 WITH THE +SOFTWARE. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 new file mode 100644 index 00000000..8aa26455 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py new file mode 100644 index 00000000..67dc9011 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -0,0 +1,68 @@ +#!/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_fix_inplace_for_each_file_path, +) + +# Actual tested checks. +from beman_tidy.lib.checks.beman_standard.license import ( + LicenseApprovedCheck, +) + +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 2.0 + Path(f"{valid_prefix}/LICENSE-v1"), + # Boost Software License 1.0 + Path(f"{valid_prefix}/LICENSE-v2"), + # MIT License + Path(f"{valid_prefix}/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 = [ + # GNU General Public License (GPL) v3.0 + Path(f"{invalid_prefix}/invalid-LICENSE-v1"), + # GNU Lesser General Public License (LGPL) v3.0 + Path(f"{invalid_prefix}/invalid-LICENSE-v2"), + # BSD-2-Clause License + Path(f"{invalid_prefix}/invalid-LICENSE-v3"), + ] + + run_check_for_each_path( + False, + invalid_license_paths, + LicenseApprovedCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="NOT implemented") +def test__LICENSE_APPROVED__fix_inplace(repo_info, beman_standard_check_config): + pass From 42218234b61872eb4e034a92f9b9948b5e078c63 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Wed, 16 Jul 2025 16:05:16 +0300 Subject: [PATCH 320/371] [beman-tidy] Run linter --- .../beman_tidy/lib/checks/beman_standard/license.py | 6 +----- .../tests/lib/checks/beman_standard/license/test_license.py | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index c7bbb95f..a2960645 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -24,11 +24,7 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): lines = self.read_lines_strip() - approved_licenses = [ - "Apache License", - "Boost Software License", - "MIT License" - ] + approved_licenses = ["Apache License", "Boost Software License", "MIT License"] for line in lines: if any(license_name in line for license_name in approved_licenses): diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index 67dc9011..b5686d30 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -6,7 +6,6 @@ from tests.utils.path_runners import ( run_check_for_each_path, - run_fix_inplace_for_each_file_path, ) # Actual tested checks. From 58a7c06f3c13d859b7299d09b73255498f9d6762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 16 Jul 2025 16:45:12 +0300 Subject: [PATCH 321/371] Sync LICENSE with exemplar/LICENSE --- LICENSE | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LICENSE b/LICENSE index 111a208f..0873f35a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,7 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ From b2ed14f8a22bb2f7da1246e744d7edf6715c3b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 16 Jul 2025 18:57:03 +0300 Subject: [PATCH 322/371] [beman-tidy] Fix README.BADGES to check for multiple badge categories --- .../beman-tidy/beman_tidy/.beman-standard.yml | 7 +++- .../lib/checks/beman_standard/readme.py | 42 +++++++++++++------ .../readme/data/invalid/invalid-badge-v1.md | 5 +-- .../readme/data/invalid/invalid-badge-v2.md | 4 +- .../readme/data/invalid/invalid-badge-v3.md | 4 +- .../readme/data/invalid/invalid-badge-v4.md | 15 +++++++ .../readme/data/invalid/invalid-badge-v5.md | 15 +++++++ .../readme/data/invalid/invalid-badge-v6.md | 15 +++++++ ...nvalid-title-v4.md => invalid-badge-v7.md} | 4 +- .../readme/data/invalid/invalid-badge-v8.md | 15 +++++++ .../readme/data/valid/README-v1.md | 2 +- .../readme/data/valid/README-v2.md | 2 +- .../readme/data/valid/README-v3.md | 2 +- .../readme/data/valid/README-v4.md | 2 +- .../beman_standard/readme/test_readme.py | 23 +++++++++- 15 files changed, 128 insertions(+), 29 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v4.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v5.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v6.md rename tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/{invalid-title-v4.md => invalid-badge-v7.md} (88%) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v8.md diff --git a/tools/beman-tidy/beman_tidy/.beman-standard.yml b/tools/beman-tidy/beman_tidy/.beman-standard.yml index b80160a6..6df8996f 100644 --- a/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ b/tools/beman-tidy/beman_tidy/.beman-standard.yml @@ -58,12 +58,17 @@ README.TITLE: - type: RECOMMENDATION README.BADGES: - type: REQUIREMENT - - values: [ + - 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)" ] + - 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: diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index b67905e4..405784c8 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -51,24 +51,40 @@ def __init__(self, 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 False @register_beman_standard_check("README.IMPLEMENTS") diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md index 5be8ed82..a322a55a 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md +++ b/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. **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: typos in badges. +This is NOT a valid README.md according to the Beman Standard: typos in badge for library status. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md index 4aa668e9..13016f51 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md @@ -3,7 +3,7 @@ -![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. @@ -12,4 +12,4 @@ **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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md index ffc08c34..128e89ea 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md @@ -3,7 +3,7 @@ -![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. @@ -12,4 +12,4 @@ **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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v4.md new file mode 100644 index 00000000..fc816d01 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v5.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v5.md new file mode 100644 index 00000000..e5a11728 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v6.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v6.md new file mode 100644 index 00000000..466d651a --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v7.md similarity index 88% rename from tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v7.md index eea29e4b..2e3d6f8f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md +++ b/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 @@ -12,4 +12,4 @@ **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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v8.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v8.md new file mode 100644 index 00000000..11d4cc46 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md index 403859dd..87e25182 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md @@ -3,7 +3,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) +![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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md index 56e5a729..f476b4b0 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md @@ -3,7 +3,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) +![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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md index dbfbacee..d742db1e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md @@ -3,7 +3,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) +![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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md index c33c6037..bf9f2038 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md @@ -3,7 +3,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) +![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. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index d660cb77..b79ecd12 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -51,11 +51,14 @@ 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( @@ -75,7 +78,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( @@ -88,9 +90,13 @@ 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"), ] @@ -109,9 +115,22 @@ def test__README_BADGES__invalid(repo_info, beman_standard_check_config): """ 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( From 28e6f9b48be72b0d6c3344e503bdc51890253fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Wed, 16 Jul 2025 22:22:17 +0300 Subject: [PATCH 323/371] [beman-tidy] Add logs for fix() methods which won't be implemented --- .../beman_tidy/lib/checks/beman_standard/readme.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py index 405784c8..5a231cae 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py @@ -84,7 +84,7 @@ def fix(self): 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 False + return True @register_beman_standard_check("README.IMPLEMENTS") @@ -122,7 +122,7 @@ 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 False + return True @register_beman_standard_check("README.LIBRARY_STATUS") @@ -148,5 +148,7 @@ 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 From d6b1ce578866ac61696e59be4b72b28346b41123 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 17 Jul 2025 14:24:08 +0300 Subject: [PATCH 324/371] [beman-tidy] Updated check and tests for LICENSE.APPROVED --- .../lib/checks/beman_standard/license.py | 60 ++++- .../license/data/invalid/invalid-LICENSE-v1 | 223 +----------------- .../license/data/invalid/invalid-LICENSE-v2 | 67 +----- .../license/data/invalid/invalid-LICENSE-v3 | 39 ++- .../license/data/valid/LICENSE-v1 | 14 +- .../license/data/valid/LICENSE-v2 | 16 ++ .../license/data/valid/LICENSE-v3 | 16 +- .../beman_standard/license/test_license.py | 8 +- 8 files changed, 128 insertions(+), 315 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index a2960645..09840a69 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -24,17 +24,59 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): lines = self.read_lines_strip() - approved_licenses = ["Apache License", "Boost Software License", "MIT License"] - - for line in lines: - if any(license_name in line for license_name in approved_licenses): - return True + separator_line = "==============================================================================" + approved_licenses = ["Apache License v2.0 with LLVM Exceptions", "Boost Software License 1.0", "MIT License"] + + # Check if license header is correct + license_header = lines[0:3] + + has_approved_license_header = False + for approved_license in approved_licenses: + if (license_header[0] == separator_line + and license_header[1] == f"The Beman Project is under the {approved_license}:" + and license_header[2] == separator_line): + has_approved_license_header = True + + if has_approved_license_header == False: + self.log( + "Incorrect header for LICENSE. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." + ) + return False + + # Check if license footer is correct + license_footer = lines[-11:] + + correct_license_footer = [ + "==============================================================================", + "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." + ] + + if license_footer != correct_license_footer: + self.log( + "Incorrect footer for LICENSE. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." + ) + return False - self.log( - f"The file '{self.path}' does not contain an approved license. " + # Check if there's any content between the header and footer + if len(lines) < 17: + self.log( + "LICENSE contains only footer and header. There should be actual license content. " "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." - ) - return False + ) + return False + + return True def fix(self): self.log( diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 index 92530788..70f3f63f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 @@ -1,220 +1,3 @@ -GNU GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 - -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -Preamble -The GNU General Public License is a free, copyleft license for software and other kinds of works. - -The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - -To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - -The precise terms and conditions for copying, distribution and modification follow. - -TERMS AND CONDITIONS 0. Definitions. -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the Program. - -To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - -To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - -1. Source Code. - The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - -The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - -The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - -2. Basic Permissions. - All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - -You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. - No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - -4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. - You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - -a) The work must carry prominent notices stating that you modified it, and giving a relevant date. -b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. -c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. -d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. -A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - -6. Conveying Non-Source Forms. - You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - -a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. -b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. -c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. -d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. -e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. -A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - -The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - -Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - -7. Additional Terms. - “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - -Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - -a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or -b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or -c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or -d) Limiting the use for publicity purposes of names of licensors or authors of the material; or -e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or -f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. -All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - -8. Termination. - You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - -9. Acceptance Not Required for Having Copies. - You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. - Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - -11. Patents. - A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - -12. No Surrender of Others' Freedom. - If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. - Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - -14. Revised Versions of this License. - The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - -Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - -15. Disclaimer of Warranty. - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. Limitation of Liability. - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. - If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. - -You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . - -The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 index f2f81d6d..b46631f4 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 @@ -1,56 +1,11 @@ -GNU LESSER GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 - -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. - -0. Additional Definitions. -As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. - -“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. - -An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. - -A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. - -The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. - -The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. - -1. Exception to Section 3 of the GNU GPL. -You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. - -2. Conveying Modified Versions. -If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: - -a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or -b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. -3. Object Code Incorporating Material from Library Header Files. -The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: - -a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. -b) Accompany the object code with a copy of the GNU GPL and this license document. -4. Combined Works. -You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: - -a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. -b) Accompany the Combined Work with a copy of the GNU GPL and this license document. -c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. -d) Do one of the following: -0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. -1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. -e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) -5. Combined Libraries. -You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: - -a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. -b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. -6. Revised Versions of the GNU Lesser General Public License. -The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. - -If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 index 9726d435..57d4582d 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v3 @@ -1,24 +1,15 @@ -BSD-2-Clause - -Copyright - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or other -materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 index 319395db..031b78de 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 @@ -1,5 +1,5 @@ ============================================================================== -The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License @@ -276,3 +276,15 @@ CONTRIBUTORS 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 WITH THE 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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 index 36b7cd93..bf24cce6 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 @@ -1,3 +1,7 @@ +============================================================================== +The Beman Project is under the Boost Software License 1.0: +============================================================================== + Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization @@ -21,3 +25,15 @@ 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. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 index 8aa26455..837e9b8e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 @@ -1,4 +1,6 @@ -MIT License +============================================================================== +The Beman Project is under the MIT License: +============================================================================== Copyright (c) [year] [fullname] @@ -19,3 +21,15 @@ 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. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index b5686d30..ca55cc88 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -23,7 +23,7 @@ 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 2.0 + # Apache License v2.0 with LLVM Exceptions Path(f"{valid_prefix}/LICENSE-v1"), # Boost Software License 1.0 Path(f"{valid_prefix}/LICENSE-v2"), @@ -45,11 +45,11 @@ def test__LICENSE_APPROVED__invalid(repo_info, beman_standard_check_config): Test that an invalid LICENSE file fails the check. """ invalid_license_paths = [ - # GNU General Public License (GPL) v3.0 + # LICENSE without header Path(f"{invalid_prefix}/invalid-LICENSE-v1"), - # GNU Lesser General Public License (LGPL) v3.0 + # LICENSE without footer Path(f"{invalid_prefix}/invalid-LICENSE-v2"), - # BSD-2-Clause License + # LICENSE with only header and footer Path(f"{invalid_prefix}/invalid-LICENSE-v3"), ] From 2bd3185e2ee59c84bf48931bcc3f2838a225b01b Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 17 Jul 2025 14:29:02 +0300 Subject: [PATCH 325/371] [beman-tidy] Run linter --- .../lib/checks/beman_standard/license.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 09840a69..d828a009 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -25,16 +25,23 @@ def check(self): lines = self.read_lines_strip() separator_line = "==============================================================================" - approved_licenses = ["Apache License v2.0 with LLVM Exceptions", "Boost Software License 1.0", "MIT License"] + approved_licenses = [ + "Apache License v2.0 with LLVM Exceptions", + "Boost Software License 1.0", + "MIT License", + ] # Check if license header is correct license_header = lines[0:3] has_approved_license_header = False for approved_license in approved_licenses: - if (license_header[0] == separator_line - and license_header[1] == f"The Beman Project is under the {approved_license}:" - and license_header[2] == separator_line): + if ( + license_header[0] == separator_line + and license_header[1] + == f"The Beman Project is under the {approved_license}:" + and license_header[2] == separator_line + ): has_approved_license_header = True if has_approved_license_header == False: @@ -58,21 +65,21 @@ def check(self): "`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." + "file.", ] if license_footer != correct_license_footer: self.log( - "Incorrect footer for LICENSE. " - "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." + "Incorrect footer for LICENSE. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." ) return False # Check if there's any content between the header and footer if len(lines) < 17: self.log( - "LICENSE contains only footer and header. There should be actual license content. " - "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." + "LICENSE contains only footer and header. There should be actual license content. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." ) return False From d68144fd37311accd775ff25fd904a84b66cc7a1 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Thu, 17 Jul 2025 14:30:47 +0300 Subject: [PATCH 326/371] [beman-tidy] Run linter --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/license.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index d828a009..ee2fe49f 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -44,7 +44,7 @@ def check(self): ): has_approved_license_header = True - if has_approved_license_header == False: + if not has_approved_license_header: self.log( "Incorrect header for LICENSE. " "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." From 4d2e0d44943ee02bd6528deeb30faff14cc7a6c9 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 09:56:44 +0300 Subject: [PATCH 327/371] [beman-tidy ] Refactored LICENSE.APPROVED check updated tests --- .../lib/checks/beman_standard/license.py | 105 +++---- .../license/data/invalid/invalid-LICENSE-v1 | 13 +- .../license/data/invalid/invalid-LICENSE-v2 | 13 +- .../license/data/invalid/invalid-LICENSE-v4 | 18 ++ .../license/data/invalid/invalid-LICENSE-v5 | 18 ++ .../license/data/valid/LICENSE-v1 | 290 ------------------ .../license/data/valid/LICENSE-v2 | 39 --- .../license/data/valid/LICENSE-v3 | 35 --- .../license/data/valid/valid-LICENSE-v1 | 18 ++ .../license/data/valid/valid-LICENSE-v2 | 18 ++ .../license/data/valid/valid-LICENSE-v3 | 18 ++ .../beman_standard/license/test_license.py | 16 +- 12 files changed, 165 insertions(+), 436 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v4 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v5 delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index ee2fe49f..f902b568 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -1,6 +1,9 @@ #!/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 ..system.registry import register_beman_standard_check @@ -22,63 +25,53 @@ 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() - - separator_line = "==============================================================================" - approved_licenses = [ - "Apache License v2.0 with LLVM Exceptions", - "Boost Software License 1.0", - "MIT License", - ] - - # Check if license header is correct - license_header = lines[0:3] - - has_approved_license_header = False - for approved_license in approved_licenses: - if ( - license_header[0] == separator_line - and license_header[1] - == f"The Beman Project is under the {approved_license}:" - and license_header[2] == separator_line - ): - has_approved_license_header = True - - if not has_approved_license_header: - self.log( - "Incorrect header for LICENSE. " - "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." - ) - return False - - # Check if license footer is correct - license_footer = lines[-11:] - - correct_license_footer = [ - "==============================================================================", - "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.", - ] - - if license_footer != correct_license_footer: - self.log( - "Incorrect footer for LICENSE. " - "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." - ) - return False - - # Check if there's any content between the header and footer - if len(lines) < 17: + content = self.read() + + # Regex pattern for LICENSE check + """ + pattern = re.compile( + r'^={78}\n' + r'The Beman Project is under the (?:Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License):\n' + r'={78}\n' + r'.+?\n' # Any content (non-greedy) + r'={78}\n' + r'Software from third parties included in the Beman Project:\n' + r'={78}\n' + r'The Beman Project contains third party software which is under different license\n' + r'terms\. All such code will be identified clearly using at least one of two\n' + r'mechanisms:\n' + r'1\) It will be in a separate directory tree with its own `LICENSE\.txt` or\n' + r' `LICENSE` file at the top containing the specific license and restrictions\n' + r' which apply to that software, or\n' + r'2\) It will contain specific license and restriction terms at the top of every\n' + r' file\.$', + re.DOTALL + ) + # """ + + # """ + pattern = re.compile( + r"""^={78} +The Beman Project is under the (Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License): +={78} +(.+?) +={78} +Software from third parties included in the Beman Project: +={78} +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\. +""", re.DOTALL) + # """ + + if not pattern.match(content): self.log( - "LICENSE contains only footer and header. There should be actual license content. " + "LICENSE file does not match the required format. " "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." ) return False diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 index 70f3f63f..e608a181 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v1 @@ -1,3 +1,14 @@ +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + ============================================================================== -The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 index b46631f4..5000cedd 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v2 @@ -1,11 +1,6 @@ ============================================================================== -Software from third parties included in the Beman Project: +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== -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. + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v4 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v4 new file mode 100644 index 00000000..993db3e2 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v4 @@ -0,0 +1,18 @@ +============================================================================== +The "Extra" Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v5 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v5 new file mode 100644 index 00000000..87d0a42a --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v5 @@ -0,0 +1,18 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +"Extra" 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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 deleted file mode 100644 index 031b78de..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v1 +++ /dev/null @@ -1,290 +0,0 @@ -============================================================================== -The Beman Project is under the Apache License v2.0 with LLVM Exceptions: -============================================================================== - - 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. - -============================================================================== -Software from third parties included in the LLVM Project: -============================================================================== -The LLVM 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. - -============================================================================== -Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -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 -CONTRIBUTORS 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 WITH THE -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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 deleted file mode 100644 index bf24cce6..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v2 +++ /dev/null @@ -1,39 +0,0 @@ -============================================================================== -The Beman Project is under the Boost Software License 1.0: -============================================================================== - -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. - -============================================================================== -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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 deleted file mode 100644 index 837e9b8e..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/LICENSE-v3 +++ /dev/null @@ -1,35 +0,0 @@ -============================================================================== -The Beman Project is under the MIT License: -============================================================================== - -Copyright (c) [year] [fullname] - -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. - -============================================================================== -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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 new file mode 100644 index 00000000..1f2a2cf2 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 @@ -0,0 +1,18 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 new file mode 100644 index 00000000..d0c84391 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v2 @@ -0,0 +1,18 @@ +============================================================================== +The Beman Project is under the Boost Software License 1.0: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 new file mode 100644 index 00000000..63876eff --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v3 @@ -0,0 +1,18 @@ +============================================================================== +The Beman Project is under the MIT License: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index ca55cc88..4817e223 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -24,11 +24,11 @@ def test__LICENSE_APPROVED__valid(repo_info, beman_standard_check_config): """ valid_license_paths = [ # Apache License v2.0 with LLVM Exceptions - Path(f"{valid_prefix}/LICENSE-v1"), + Path(f"{valid_prefix}/valid-LICENSE-v1"), # Boost Software License 1.0 - Path(f"{valid_prefix}/LICENSE-v2"), + Path(f"{valid_prefix}/valid-LICENSE-v2"), # MIT License - Path(f"{valid_prefix}/LICENSE-v3"), + Path(f"{valid_prefix}/valid-LICENSE-v3"), ] run_check_for_each_path( @@ -45,12 +45,16 @@ def test__LICENSE_APPROVED__invalid(repo_info, beman_standard_check_config): Test that an invalid LICENSE file fails the check. """ invalid_license_paths = [ - # LICENSE without header + # Almost valid LICENSE, but without header Path(f"{invalid_prefix}/invalid-LICENSE-v1"), - # LICENSE without footer + # Almost valid LICENSE, but without footer Path(f"{invalid_prefix}/invalid-LICENSE-v2"), - # LICENSE with only header and footer + # Almost valid LICENSE, but not content between header and footer Path(f"{invalid_prefix}/invalid-LICENSE-v3"), + # Almost valid LICENSE, but not exact header + Path(f"{invalid_prefix}/invalid-LICENSE-v4"), + # Almost valid LICENSE, but not exact footer + Path(f"{invalid_prefix}/invalid-LICENSE-v5"), ] run_check_for_each_path( From 13236ab97d4f76d357f2d62ce228a61cf93cbb45 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 09:59:12 +0300 Subject: [PATCH 328/371] [beman-tidy] Run linter --- .../beman_tidy/lib/checks/beman_standard/license.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index f902b568..a4643760 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import re -import textwrap from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check @@ -66,7 +65,9 @@ def check(self): which apply to that software, or 2\) It will contain specific license and restriction terms at the top of every file\. -""", re.DOTALL) +""", + re.DOTALL, + ) # """ if not pattern.match(content): From 15d92ebf006813cd77eafeb3f3cbba643d6c98ac Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 11:16:28 +0300 Subject: [PATCH 329/371] [beman-tidy] Removed dead code --- .../lib/checks/beman_standard/license.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index a4643760..8548eb29 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -27,28 +27,6 @@ def check(self): content = self.read() # Regex pattern for LICENSE check - """ - pattern = re.compile( - r'^={78}\n' - r'The Beman Project is under the (?:Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License):\n' - r'={78}\n' - r'.+?\n' # Any content (non-greedy) - r'={78}\n' - r'Software from third parties included in the Beman Project:\n' - r'={78}\n' - r'The Beman Project contains third party software which is under different license\n' - r'terms\. All such code will be identified clearly using at least one of two\n' - r'mechanisms:\n' - r'1\) It will be in a separate directory tree with its own `LICENSE\.txt` or\n' - r' `LICENSE` file at the top containing the specific license and restrictions\n' - r' which apply to that software, or\n' - r'2\) It will contain specific license and restriction terms at the top of every\n' - r' file\.$', - re.DOTALL - ) - # """ - - # """ pattern = re.compile( r"""^={78} The Beman Project is under the (Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License): @@ -68,7 +46,6 @@ def check(self): """, re.DOTALL, ) - # """ if not pattern.match(content): self.log( From 0b808d9ab757cabbb6ee25a149dec37a9bf26751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Fri, 18 Jul 2025 11:29:35 +0300 Subject: [PATCH 330/371] [beman-tidy] Prettier regex with textwrap --- .../lib/checks/beman_standard/license.py | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 8548eb29..352a219c 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import re +import textwrap from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check @@ -28,22 +29,23 @@ def check(self): # Regex pattern for LICENSE check pattern = re.compile( - r"""^={78} -The Beman Project is under the (Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License): -={78} -(.+?) -={78} -Software from third parties included in the Beman Project: -={78} -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\. -""", + textwrap.dedent(r""" + ^={78} + The Beman Project is under the (Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License): + ={78} + (.+?) + ={78} + Software from third parties included in the Beman Project: + ={78} + 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\. + """).strip(), re.DOTALL, ) From 50e4123b9c0c5a14d62843a0d19638d20c92280c Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 11:41:59 +0300 Subject: [PATCH 331/371] [beman-tidy] Clearer regex comment --- .../beman_tidy/lib/checks/beman_standard/license.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 352a219c..bbaddbdb 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -27,8 +27,8 @@ def __init__(self, repo_info, beman_standard_check_config): def check(self): content = self.read() - # Regex pattern for LICENSE check - pattern = re.compile( + # Regex for LICENSE check + regex = re.compile( textwrap.dedent(r""" ^={78} The Beman Project is under the (Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License): @@ -49,7 +49,7 @@ def check(self): re.DOTALL, ) - if not pattern.match(content): + if not regex.match(content): self.log( "LICENSE file does not match the required format. " "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#licenseapproved for more information." From 12d69858254653fdf35efb63e415c989ac80dc54 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 11:50:59 +0300 Subject: [PATCH 332/371] [beman-tidy] Clearer comments for regex --- .../beman_tidy/lib/checks/beman_standard/license.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index bbaddbdb..a2a5615d 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -28,12 +28,17 @@ def check(self): content = self.read() # Regex for LICENSE check + # - fixed header matching + # - non empty body matching + # - fixed footer matching regex = re.compile( textwrap.dedent(r""" ^={78} The Beman Project is under the (Apache License v2\.0 with LLVM Exceptions|Boost Software License 1\.0|MIT License): ={78} + (.+?) + ={78} Software from third parties included in the Beman Project: ={78} From bf09463e0403bdffdf29d046c54066e7665ca1bd Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 12:59:17 +0300 Subject: [PATCH 333/371] [beman-tidy] Added check, fix and tests for LICENSE.APACHE_LLVM --- .../lib/checks/beman_standard/license.py | 28 ++- .../license/data/invalid/invalid-LICENSE-v6 | 18 ++ .../license/data/invalid/invalid-LICENSE-v7 | 18 ++ .../license/data/valid/valid-LICENSE-v1 | 220 +++++++++++++++++- .../beman_standard/license/test_license.py | 44 ++++ 5 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v6 create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v7 diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index a2a5615d..72b04fa3 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -70,7 +70,33 @@ def fix(self): ) -# 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): + # path/to/repo/LICENSE content + content = self.read() + + # infra LICENSE content + with open("../../LICENSE", "r") as f: + infra_license = f.read() + + if content != infra_license: + 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." + ) # TODO LICENSE.CRITERIA diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v6 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v6 new file mode 100644 index 00000000..d0c84391 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v6 @@ -0,0 +1,18 @@ +============================================================================== +The Beman Project is under the Boost Software License 1.0: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v7 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v7 new file mode 100644 index 00000000..63876eff --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/invalid/invalid-LICENSE-v7 @@ -0,0 +1,18 @@ +============================================================================== +The Beman Project is under the MIT License: +============================================================================== + +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 index 1f2a2cf2..0873f35a 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 @@ -2,8 +2,224 @@ The Beman Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== -# Dummy LICENSE lines. -# beman-tidy does not actually check the content between the header and the footer. + 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. ============================================================================== Software from third parties included in the Beman Project: diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index 4817e223..7097c688 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -11,6 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.license import ( LicenseApprovedCheck, + LicenseApacheLLVMCheck ) test_data_prefix = "tests/lib/checks/beman_standard/license/data" @@ -69,3 +70,46 @@ def test__LICENSE_APPROVED__invalid(repo_info, beman_standard_check_config): @pytest.mark.skip(reason="NOT implemented") def test__LICENSE_APPROVED__fix_inplace(repo_info, beman_standard_check_config): 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 + 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 + Path(f"{invalid_prefix}/invalid-LICENSE-v6"), + # MIT License + Path(f"{invalid_prefix}/invalid-LICENSE-v7"), + ] + + 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): + pass From fae5e16bd199d1094c5fce6c2493886469cdc166 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 13:01:51 +0300 Subject: [PATCH 334/371] [beman-tidy] Run linter --- .../tests/lib/checks/beman_standard/license/test_license.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index 7097c688..fc72b658 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -11,7 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.license import ( LicenseApprovedCheck, - LicenseApacheLLVMCheck + LicenseApacheLLVMCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/license/data" From 8e56cf36a8dcbac17ae4cbb35febbef9fcf0f1fe Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 14:36:02 +0300 Subject: [PATCH 335/371] [beman-tidy] Added clearer check and tests --- .../lib/checks/beman_standard/license.py | 13 +- .../license/data/valid/valid-LICENSE-v1 | 220 +--------------- .../license/data/valid/valid-LICENSE-v4 | 234 ++++++++++++++++++ .../beman_standard/license/test_license.py | 8 +- 4 files changed, 246 insertions(+), 229 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v4 diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 72b04fa3..e347dfd4 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -2,7 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import re +import filecmp import textwrap +from pathlib import Path from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check @@ -76,14 +78,11 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - # path/to/repo/LICENSE content - content = self.read() - - # infra LICENSE content - with open("../../LICENSE", "r") as f: - infra_license = f.read() + # Compare LICENSE file stored at self.path with the reference one. + target_license = self.path + ref_license = Path(__file__).parents[6] / "LICENSE" - if content != infra_license: + 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." diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 index 0873f35a..1f2a2cf2 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v1 @@ -2,224 +2,8 @@ The Beman Project is under the Apache License v2.0 with LLVM Exceptions: ============================================================================== - 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. +# Dummy LICENSE lines. +# beman-tidy does not actually check the content between the header and the footer. ============================================================================== Software from third parties included in the Beman Project: diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v4 b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v4 new file mode 100644 index 00000000..0873f35a --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/data/valid/valid-LICENSE-v4 @@ -0,0 +1,234 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + 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. + +============================================================================== +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/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index fc72b658..1fa75da3 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -77,8 +77,8 @@ 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 - Path(f"{valid_prefix}/valid-LICENSE-v1"), + # Apache License v2.0 with LLVM Exceptions is the only one compatible with LICENSE.APACHE_LLVM. + Path(f"{valid_prefix}/valid-LICENSE-v4"), ] run_check_for_each_path( @@ -95,9 +95,9 @@ 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 + # Boost Software License 1.0 is LICENSE.APPROVED compatible, but not compatible with LICENSE.APACHE_LLVM. Path(f"{invalid_prefix}/invalid-LICENSE-v6"), - # MIT License + # MIT License is LICENSE.APPROVED compatible, but not compatible with LICENSE.APACHE_LLVM. Path(f"{invalid_prefix}/invalid-LICENSE-v7"), ] From e7c0dae3ba09628f604f8466735c697dbf6b6d15 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 14:37:00 +0300 Subject: [PATCH 336/371] [beman-tidy] Run linter --- .../beman-tidy/beman_tidy/lib/checks/beman_standard/license.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index e347dfd4..28e53bdd 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -82,7 +82,7 @@ def check(self): target_license = self.path ref_license = Path(__file__).parents[6] / "LICENSE" - if not filecmp.cmp(target_license, ref_license, shallow=False): + 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." From 018212cdf7ee0a0600bd0bf79ff99a2760479655 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 14:46:03 +0300 Subject: [PATCH 337/371] [beman-tidy] Remove space --- tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 28e53bdd..f97918af 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -81,7 +81,6 @@ def check(self): # Compare LICENSE file stored at self.path with the reference one. target_license = self.path ref_license = Path(__file__).parents[6] / "LICENSE" - 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. " From 39bcc5801bff99cbdb13d21ec769422f5a32f950 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 15:39:17 +0300 Subject: [PATCH 338/371] [beman-tidy] Added check for LICENSE.CRITERIA --- .../lib/checks/beman_standard/license.py | 20 +++++++++++++++++-- .../beman_standard/license/test_license.py | 14 +++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index f97918af..8520fcf6 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -8,7 +8,7 @@ from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check - +from ....lib.utils.git import load_beman_standard_config, get_repo_info # [LICENSE.*] checks category. # All checks in this file extend the LicenseBaseCheck class. @@ -97,4 +97,20 @@ def fix(self): ) -# TODO LICENSE.CRITERIA +@register_beman_standard_check("LICENSE.CRITERIA") +class LicenseCriteriaCheck(LicenseBaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + 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 + + def fix(self): + 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." + ) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index 1fa75da3..c1691535 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -12,6 +12,7 @@ from beman_tidy.lib.checks.beman_standard.license import ( LicenseApprovedCheck, LicenseApacheLLVMCheck, + LicenseCriteriaCheck ) test_data_prefix = "tests/lib/checks/beman_standard/license/data" @@ -113,3 +114,16 @@ def test__LICENSE_APACHE_LLVM__invalid(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): pass + + +def test__LICENSE_CRITERIA__valid(repo_info, beman_standard_check_config): + pass + + +def test__LICENSE_CRITERIA__invalid(repo_info, beman_standard_check_config): + pass + + +@pytest.mark.skip(reason="NOT implemented") +def test__LICENSE_CRITERIA__fix_inplace(repo_info, beman_standard_check_config): + pass From a1097008576be5406abd7df4541de61c103ab26e Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 15:44:34 +0300 Subject: [PATCH 339/371] [beman-tidy] Run linter --- .../tests/lib/checks/beman_standard/license/test_license.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index c1691535..93e5bffc 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -12,7 +12,6 @@ from beman_tidy.lib.checks.beman_standard.license import ( LicenseApprovedCheck, LicenseApacheLLVMCheck, - LicenseCriteriaCheck ) test_data_prefix = "tests/lib/checks/beman_standard/license/data" From 0cc6be81c5f6f80716cf02829115c4fb7e08d8d7 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 15:45:41 +0300 Subject: [PATCH 340/371] [beman-tidy] Run linter --- tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 8520fcf6..7a645453 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -8,7 +8,6 @@ from ..base.file_base_check import FileBaseCheck from ..system.registry import register_beman_standard_check -from ....lib.utils.git import load_beman_standard_config, get_repo_info # [LICENSE.*] checks category. # All checks in this file extend the LicenseBaseCheck class. From fe154fe06a15e560e51b61a517102036406cdca8 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 16:22:30 +0300 Subject: [PATCH 341/371] [beman-tidy] Added tests and comments --- .../beman_standard/license/test_license.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index 93e5bffc..ab892bdd 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -12,6 +12,7 @@ from beman_tidy.lib.checks.beman_standard.license import ( LicenseApprovedCheck, LicenseApacheLLVMCheck, + LicenseCriteriaCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/license/data" @@ -116,13 +117,39 @@ def test__LICENSE_APACHE_LLVM__fix_inplace(repo_info, beman_standard_check_confi def test__LICENSE_CRITERIA__valid(repo_info, beman_standard_check_config): - pass + valid_license_paths = [ + # Apache License v2.0 with LLVM Exceptions + Path(f"{valid_prefix}/valid-LICENSE-v1"), + ] + + run_check_for_each_path( + True, + valid_license_paths, + LicenseCriteriaCheck, + repo_info, + beman_standard_check_config, + ) +@pytest.mark.skip(reason="NOT implemented") def test__LICENSE_CRITERIA__invalid(repo_info, beman_standard_check_config): + # LICENSE.CRITERIA cannot be invalid. Check license.py. + invalid_license_paths = [ + # Almost valid LICENSE, but without header + Path(f"{invalid_prefix}/invalid-LICENSE-v1"), + ] + + run_check_for_each_path( + False, + invalid_license_paths, + LicenseCriteriaCheck, + repo_info, + beman_standard_check_config, + ) pass @pytest.mark.skip(reason="NOT implemented") def test__LICENSE_CRITERIA__fix_inplace(repo_info, beman_standard_check_config): + # LICENSE.CRITERIA cannot be invalid, so no need for fix inplace. Check license.py. pass From 54efbdcafd3908a3ff3d6239c32b6dc00619aec9 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Fri, 18 Jul 2025 16:56:06 +0300 Subject: [PATCH 342/371] [beman-tidy] Updated tests --- .../beman_standard/license/test_license.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py index ab892bdd..4a6fab93 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/license/test_license.py @@ -118,8 +118,10 @@ def test__LICENSE_APACHE_LLVM__fix_inplace(repo_info, beman_standard_check_confi def test__LICENSE_CRITERIA__valid(repo_info, beman_standard_check_config): valid_license_paths = [ - # Apache License v2.0 with LLVM Exceptions + # LICENSE.CRITERIA is always true, e.g. for valid file with Apache License v2.0 with LLVM Exceptions. Path(f"{valid_prefix}/valid-LICENSE-v1"), + # LICENSE.CRITERIA is always true, e.g. for invalid file. + Path(f"{invalid_prefix}/invalid-LICENSE-v1"), ] run_check_for_each_path( @@ -134,18 +136,6 @@ def test__LICENSE_CRITERIA__valid(repo_info, beman_standard_check_config): @pytest.mark.skip(reason="NOT implemented") def test__LICENSE_CRITERIA__invalid(repo_info, beman_standard_check_config): # LICENSE.CRITERIA cannot be invalid. Check license.py. - invalid_license_paths = [ - # Almost valid LICENSE, but without header - Path(f"{invalid_prefix}/invalid-LICENSE-v1"), - ] - - run_check_for_each_path( - False, - invalid_license_paths, - LicenseCriteriaCheck, - repo_info, - beman_standard_check_config, - ) pass From aa23f1a966bc416dd422128ec9b93a710f1d7c28 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 14:29:39 +0300 Subject: [PATCH 343/371] [beman-tidy] Added check and tests for REPOSITORY.DISALLOW_GIT_SUBMODULES --- .../lib/checks/beman_standard/repository.py | 43 +++++++++++++- .../data/invalid/repo-exemplar-v1/.gitmodules | 3 + .../data/invalid/repo-exemplar-v2/.gitmodules | 9 +++ .../data/invalid/repo-exemplar-v3/.gitmodules | 6 ++ .../data/valid/repo-exemplar-v2/.gitmodules | 3 + .../repository/test_repository.py | 56 +++++++++++++++++++ 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index 6745dbe8..da85b790 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -1,6 +1,9 @@ #!/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 @@ -49,4 +52,42 @@ def fix(self): ) -# TODO REPOSITORY.DISALLOW_GIT_SUBMODULES +@register_beman_standard_check("REPOSITORY.DISALLOW_GIT_SUBMODULES") +class RepositoryDisallowGitSubmodulesCheck(BaseCheck): + def __init__(self, repo_info, beman_standard_check_config): + super().__init__(repo_info, beman_standard_check_config) + + def check(self): + # Regex pattern to match "wg21" submodule + regex = re.compile( + textwrap.dedent(r""" + ^\[submodule \"wg21\"] + \tpath = wg21 + \turl = https://github.com/mpark/wg21.git$ + """).strip() + ) + + gitsubmodules_path = self.repo_path / ".gitmodules" + + # Check if .gitmodules file exists and is different from wg21 + if gitsubmodules_path.exists(): + with open(gitsubmodules_path, "r") as f: + content = f.read() + + 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 + return True + + def fix(self): + self.log( + "Please remove git submodules. " + "Known exception: wg21. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#repositorydisallow_git_submodules for more information." + ) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules new file mode 100644 index 00000000..b2ab191a --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules @@ -0,0 +1,3 @@ +[submodule "papers"] + path = papers + url = https://github.com/cplusplus/papers \ No newline at end of file diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules new file mode 100644 index 00000000..f8ba85a1 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules @@ -0,0 +1,9 @@ +[submodule "dummy"] + path = dummy + url = https://github.com/dummy.git +[submodule "wg21"] + path = wg21 + url = https://github.com/mpark/wg21.git +[submodule "papers"] + path = papers + url = https://github.com/cplusplus/papers diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules new file mode 100644 index 00000000..6eeedbd8 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules @@ -0,0 +1,6 @@ +[submodule "dummy"] + path = dummy + url = https://github.com/dummy.git +[submodule "papers"] + path = papers + url = https://github.com/cplusplus/papers diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules new file mode 100644 index 00000000..5c1726eb --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules @@ -0,0 +1,3 @@ +[submodule "wg21"] + path = wg21 + url = https://github.com/mpark/wg21.git diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index c26989df..41e2cdae 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -3,6 +3,8 @@ import pytest from pathlib import Path +from git.objects.submodule.base import Submodule +from unittest.mock import Mock from tests.utils.path_runners import ( run_check_for_each_path, @@ -13,6 +15,7 @@ from beman_tidy.lib.checks.beman_standard.repository import ( RepositoryCodeownersCheck, RepositoryDefaultBranchCheck, + RepositoryDisallowGitSubmodulesCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/repository/data" @@ -115,3 +118,56 @@ def test__REPOSITORY_DEFAULT_BRANCH__fix_inplace( repo_info, beman_standard_check_config ): pass + + +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 + Path(f"{valid_prefix}/repo-exemplar-v1/"), + # Repo with wg21 git submodule + Path(f"{valid_prefix}/repo-exemplar-v2/"), + ] + + 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__inplace( + repo_info, beman_standard_check_config +): + pass From 8f57dcaead3fb806b370f1f6f86aab660919bf55 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 14:35:16 +0300 Subject: [PATCH 344/371] [beman-tidy] Run linter --- .../lib/checks/beman_standard/repository/test_repository.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 41e2cdae..f2bcbe48 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -3,8 +3,6 @@ import pytest from pathlib import Path -from git.objects.submodule.base import Submodule -from unittest.mock import Mock from tests.utils.path_runners import ( run_check_for_each_path, From f8965aea8fecec8a2f1be6864b8aa068f15a522b Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 14:38:00 +0300 Subject: [PATCH 345/371] [beman-tidy] Run linter --- .../repository/data/invalid/repo-exemplar-v1/.gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules index b2ab191a..0dfcc4e6 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules @@ -1,3 +1,3 @@ [submodule "papers"] path = papers - url = https://github.com/cplusplus/papers \ No newline at end of file + url = https://github.com/cplusplus/papers From 211fccc8a6940f60b52bf4e79bb19d4c173b964c Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 16:07:17 +0300 Subject: [PATCH 346/371] [beman-tidy] Added check, fix and tests for REPOSITORY.NAME --- .../lib/checks/beman_standard/repository.py | 40 +++++++++++++++- .../repository/test_repository.py | 46 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index 6745dbe8..2543ad4a 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import re + from ..base.file_base_check import FileBaseCheck from ..base.base_check import BaseCheck from ..system.registry import register_beman_standard_check @@ -11,7 +13,43 @@ # Note: FileBaseCheck is not a registered check! -# TODO REPOSITORY.NAME +@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): + def is_snake_case(name): + return re.match("(^[a-z0-9]+$)|(^[a-z0-9][a-z0-9_.]+[a-z0-9]$)", name) + + def is_beman_snake_case(name): + """ + Has prefix "beman." and continues with snake_case. + It must NOT end with a C++ target standard version - e.g. 17, 20, 23, 26, 32, etc. + """ + return ( + name[:6] != "beman." + and is_snake_case(name) + and not re.match(".*[0-9]+$", name) + ) + + name = self.repo_info["name"] + + if not is_beman_snake_case(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 since that would require GitHub API calls and administrative permissions. " + "Please see https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#repositoryname for more information." + ) + pass @register_beman_standard_check("REPOSITORY.CODEOWNERS") diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index c26989df..82e3c28e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -13,6 +13,7 @@ from beman_tidy.lib.checks.beman_standard.repository import ( RepositoryCodeownersCheck, RepositoryDefaultBranchCheck, + RepositoryNameCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/repository/data" @@ -20,6 +21,51 @@ 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"}, + ] + + 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"}, + ] + + 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): + pass + + def test__REPOSITORY_CODEOWNERS__valid(repo_info, beman_standard_check_config): """ Test that repositories with valid CODEOWNERS pass the check. From 54eea15f341de2b681ba970ed068a4ea29285ea7 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 22:00:12 +0300 Subject: [PATCH 347/371] [beman-tidy] Simplify repo name check and added tests --- .../lib/checks/beman_standard/repository.py | 24 ++++--------------- .../beman-tidy/beman_tidy/lib/utils/string.py | 6 ++--- .../repository/test_repository.py | 6 +++++ 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index 2543ad4a..2365168a 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -import re - 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. @@ -19,23 +18,8 @@ def __init__(self, repo_info, beman_standard_check_config): super().__init__(repo_info, beman_standard_check_config) def check(self): - def is_snake_case(name): - return re.match("(^[a-z0-9]+$)|(^[a-z0-9][a-z0-9_.]+[a-z0-9]$)", name) - - def is_beman_snake_case(name): - """ - Has prefix "beman." and continues with snake_case. - It must NOT end with a C++ target standard version - e.g. 17, 20, 23, 26, 32, etc. - """ - return ( - name[:6] != "beman." - and is_snake_case(name) - and not re.match(".*[0-9]+$", name) - ) - - name = self.repo_info["name"] - - if not is_beman_snake_case(name): + 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." @@ -46,7 +30,7 @@ def is_beman_snake_case(name): def fix(self): self.log( - "beman-tidy can't automatically fix the repository name since that would require GitHub API calls and administrative permissions. " + "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 diff --git a/tools/beman-tidy/beman_tidy/lib/utils/string.py b/tools/beman-tidy/beman_tidy/lib/utils/string.py index 07329da2..2982c683 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/string.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/string.py @@ -15,9 +15,9 @@ 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) ) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 82e3c28e..73f0a19a 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -30,6 +30,9 @@ def test__REPOSITORY_NAME__valid(repo_info, beman_standard_check_config): 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( @@ -51,6 +54,9 @@ def test__REPOSITORY_NAME__invalid(repo_info, beman_standard_check_config): 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( From a52ce631c221c9f30b3a5fc7b41a7c0a322addec Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 22:01:24 +0300 Subject: [PATCH 348/371] [beman-tidy] Run linter --- tools/beman-tidy/beman_tidy/lib/utils/string.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/utils/string.py b/tools/beman-tidy/beman_tidy/lib/utils/string.py index 2982c683..e9ccf705 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/string.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/string.py @@ -15,9 +15,7 @@ def is_beman_snake_case(name): """ return ( - name[:6] != "beman." - and is_snake_case(name) - and not re.match(".*[0-9]+$", name) + name[:6] != "beman." and is_snake_case(name) and not re.match(".*[0-9]+$", name) ) From 96aab3193768054990475c2570a96148e58046f3 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 14:35:16 +0300 Subject: [PATCH 349/371] [beman-tidy] Run linter --- .../lib/checks/beman_standard/repository/test_repository.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 41e2cdae..f2bcbe48 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -3,8 +3,6 @@ import pytest from pathlib import Path -from git.objects.submodule.base import Submodule -from unittest.mock import Mock from tests.utils.path_runners import ( run_check_for_each_path, From 02be284ef01c98bac6205c88055f1a5b6d9e44fb Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 23:29:30 +0300 Subject: [PATCH 350/371] [beman-tidy] Revert changes --- .../repository/test_repository.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index f2bcbe48..079fcb30 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -11,6 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.repository import ( + RepositoryNameCheck, RepositoryCodeownersCheck, RepositoryDefaultBranchCheck, RepositoryDisallowGitSubmodulesCheck, @@ -21,6 +22,57 @@ 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): + pass + + def test__REPOSITORY_CODEOWNERS__valid(repo_info, beman_standard_check_config): """ Test that repositories with valid CODEOWNERS pass the check. From 4de0aac6c74aaf6261bc472edb1782634a29bf72 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 23:50:33 +0300 Subject: [PATCH 351/371] [beman-tidy] Simplified check and changed tests --- .../lib/checks/beman_standard/repository.py | 36 +++++++++---------- .../data/invalid/repo-exemplar-v1/.gitmodules | 6 ++-- .../data/invalid/repo-exemplar-v2/.gitmodules | 12 +++---- .../data/invalid/repo-exemplar-v3/.gitmodules | 12 +++---- .../data/valid/repo-exemplar-v3/.gitmodules | 3 ++ .../repository/test_repository.py | 4 ++- 6 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v3/.gitmodules diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index dbd21a44..10d59fb0 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -75,26 +75,26 @@ def fix(self): @register_beman_standard_check("REPOSITORY.DISALLOW_GIT_SUBMODULES") -class RepositoryDisallowGitSubmodulesCheck(BaseCheck): +class RepositoryDisallowGitSubmodulesCheck(FileBaseCheck): def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - # Regex pattern to match "wg21" submodule - regex = re.compile( - textwrap.dedent(r""" - ^\[submodule \"wg21\"] - \tpath = wg21 - \turl = https://github.com/mpark/wg21.git$ - """).strip() - ) + super().__init__(repo_info, beman_standard_check_config, ".gitmodules") - gitsubmodules_path = self.repo_path / ".gitmodules" + def pre_check(self): + # Need to override this, because REPOSITORY.DISALLOW_GIT_SUBMODULES is conditional + return True - # Check if .gitmodules file exists and is different from wg21 - if gitsubmodules_path.exists(): - with open(gitsubmodules_path, "r") as f: - content = f.read() + 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 = (?:.+?/)?wg21 + \turl = https://github.com/mpark/wg21.git$ + """).strip() + ) if not regex.match(content): self.log( @@ -104,7 +104,7 @@ def check(self): ) return False - # Check passes if .gitmodules file doesn't exist + # Check passes if .gitmodules file doesn't exist or if it only contains wg21 submodule. return True def fix(self): diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules index 0dfcc4e6..d438b89b 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v1/.gitmodules @@ -1,3 +1,3 @@ -[submodule "papers"] - path = papers - url = https://github.com/cplusplus/papers +[submodule "dummy"] + path = dummy + url = https://github.com/cplusplus/dummy diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules index f8ba85a1..cb06c9ef 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v2/.gitmodules @@ -1,9 +1,9 @@ -[submodule "dummy"] - path = dummy - url = https://github.com/dummy.git +[submodule "dummy1"] + path = dummy1 + url = https://github.com/dummy1.git [submodule "wg21"] path = wg21 url = https://github.com/mpark/wg21.git -[submodule "papers"] - path = papers - url = https://github.com/cplusplus/papers +[submodule "dummy2"] + path = dummy2 + url = https://github.com/cplusplus/dummy2 diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules index 6eeedbd8..ee23af06 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules @@ -1,6 +1,6 @@ -[submodule "dummy"] - path = dummy - url = https://github.com/dummy.git -[submodule "papers"] - path = papers - url = https://github.com/cplusplus/papers +[submodule "dummy1"] + path = dummy1 + url = https://github.com/dummy1.git +[submodule "dummy2"] + path = dummy2 + url = https://github.com/cplusplus/dummy2 \ No newline at end of file diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v3/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v3/.gitmodules new file mode 100644 index 00000000..b44d8c09 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py index 079fcb30..7538f77f 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/test_repository.py @@ -177,10 +177,12 @@ def test__REPOSITORY_DISALLOW_GIT_SUBMODULES__valid( Test that repositories with valid git submodules pass the check. """ valid_submodules_paths = [ - # Repo with no .gitsubmodules + # 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( From d54d51cec78fd27354462595f139da9675a56b40 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sat, 19 Jul 2025 23:52:42 +0300 Subject: [PATCH 352/371] [beman-tidy] Run linter --- .../repository/data/invalid/repo-exemplar-v3/.gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules index ee23af06..50ecb2b4 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/invalid/repo-exemplar-v3/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/dummy1.git [submodule "dummy2"] path = dummy2 - url = https://github.com/cplusplus/dummy2 \ No newline at end of file + url = https://github.com/cplusplus/dummy2 From f2fc6b7f5d0c445f1ed7cfe4324626915eb297ef Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 20 Jul 2025 00:14:24 +0300 Subject: [PATCH 353/371] [beman-tidy] Added clearer log message for fix --- .../beman_tidy/lib/checks/beman_standard/repository.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index 10d59fb0..520488eb 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -91,7 +91,7 @@ def check(self): regex = re.compile( textwrap.dedent(r""" ^\[submodule \"(?:.+?/)?wg21\"] - \tpath = (?:.+?/)?wg21 + \tpath = (.+?) \turl = https://github.com/mpark/wg21.git$ """).strip() ) @@ -109,7 +109,6 @@ def check(self): def fix(self): self.log( - "Please remove git submodules. " - "Known exception: wg21. " + "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." ) From 621d444583a2cbd00ea152c21d01d5feae034708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 01:50:51 +0300 Subject: [PATCH 354/371] [beman-tidy] Implement RELEASE.GODBOLT_TRUNK_VERSION --- .../lib/checks/beman_standard/release.py | 35 ++++++++++- .../checks/beman_standard/release/__init__.py | 0 .../checks/beman_standard/release/conftest.py | 16 +++++ .../data/invalid/repo-exemplar-v1/README.md | 28 +++++++++ .../data/valid/repo-exemplar-v1/README.md | 28 +++++++++ .../beman_standard/release/test_release.py | 63 +++++++++++++++++++ 6 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/release/__init__.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/release/conftest.py create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/release/data/invalid/repo-exemplar-v1/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/release/data/valid/repo-exemplar-v1/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py index 6c2f59b1..edfbd9df 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py @@ -1,6 +1,10 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import re +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? @@ -12,4 +16,33 @@ # TODO RELEASE.NOTES -# TODO RELEASE.GODBOLT_TRUNK_VERSION +@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) + + 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. + """ + + 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 + + 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/tools/beman-tidy/tests/lib/checks/beman_standard/release/__init__.py b/tools/beman-tidy/tests/lib/checks/beman_standard/release/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/release/conftest.py b/tools/beman-tidy/tests/lib/checks/beman_standard/release/conftest.py new file mode 100644 index 00000000..515dc2bd --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/invalid/repo-exemplar-v1/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/invalid/repo-exemplar-v1/README.md new file mode 100644 index 00000000..a4326df7 --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/valid/repo-exemplar-v1/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/release/data/valid/repo-exemplar-v1/README.md new file mode 100644 index 00000000..c1ddce1f --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py new file mode 100644 index 00000000..c0440a3b --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py @@ -0,0 +1,63 @@ +#!/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 ( + ReleaseGodboltTrunkVersionCheck, +) + +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_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 +): + pass From e01c9cb43a4a0aca89ad3194f00e66ab6259f6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 02:00:35 +0300 Subject: [PATCH 355/371] [beman-tidy] Implement RELEASE.GITHUB --- .../lib/checks/beman_standard/release.py | 22 ++++++++++-- .../beman_standard/release/test_release.py | 35 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py index edfbd9df..25b61d0e 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py @@ -2,15 +2,33 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 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. -# TODO RELEASE.GITHUB +@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 check(self): + # Need to always return True, as beman-tidy is an offline tool + # that does not have access to the GitHub API. + self.log( + "beman-tidy cannot check this issue. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#releasegithub." + ) + return True + + def fix(self): + self.log( + "beman-tidy cannot fix this issue. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#releasegithub." + ) # TODO RELEASE.NOTES diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py index c0440a3b..dac5c0d3 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py @@ -10,6 +10,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.release import ( + ReleaseGithubCheck, ReleaseGodboltTrunkVersionCheck, ) @@ -18,6 +19,40 @@ invalid_prefix = f"{test_data_prefix}/invalid" +def test__RELEASE_GITHUB__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with GitHub release pass the check. + """ + valid_repo_paths = [ + # RELEASE.GITHUB always passes, as beman-tidy is an offline tool. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_repo_paths, + ReleaseGithubCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="NOT implemented") +def test__RELEASE_GITHUB__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with missing GitHub release fail the check. + """ + # RELEASE.GITHUB always passes, as beman-tidy is an offline tool. + pass + + +@pytest.mark.skip(reason="NOT implemented") +def test__RELEASE_GITHUB__fix_inplace(repo_info, beman_standard_check_config): + # RELEASE.GITHUB always passes, as beman-tidy is an offline tool. + pass + + def test__RELEASE_GODBOLT_TRUNK_VERSION__valid(repo_info, beman_standard_check_config): """ Test that repositories with present Godbolt trunk version pass the check. From 8a3b7d889e3937583842a6d246c866ca884c9ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 02:02:33 +0300 Subject: [PATCH 356/371] [beman-tidy] Implement RELEASE.NOTES --- .../lib/checks/beman_standard/release.py | 17 +++++++++ .../beman_standard/release/test_release.py | 38 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py index 25b61d0e..1d306b8f 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py @@ -32,6 +32,23 @@ def fix(self): # TODO RELEASE.NOTES +@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 check(self): + # Need to always return True, as beman-tidy is an offline tool + # that does not have access to the GitHub API. + self.log( + "beman-tidy cannot check this issue. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#releasenotes." + ) + return True + + def fix(self): + self.log( + "beman-tidy cannot fix this issue. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#releasenotes." + ) @register_beman_standard_check("RELEASE.GODBOLT_TRUNK_VERSION") diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py index dac5c0d3..f9a72fab 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py @@ -12,6 +12,7 @@ from beman_tidy.lib.checks.beman_standard.release import ( ReleaseGithubCheck, ReleaseGodboltTrunkVersionCheck, + ReleaseNotesCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/release/data" @@ -53,6 +54,43 @@ def test__RELEASE_GITHUB__fix_inplace(repo_info, beman_standard_check_config): pass +def test__RELEASE_NOTES__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with release notes pass the check. + """ + valid_repo_paths = [ + # RELEASE.NOTES always passes, as beman-tidy is an offline tool. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + Path(f"{invalid_prefix}/repo-exemplar-v1/"), + ] + + run_check_for_each_path( + True, + valid_repo_paths, + ReleaseNotesCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="NOT implemented") +def test__RELEASE_NOTES__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with missing release notes fail the check. + """ + # RELEASE.NOTES always passes, as beman-tidy is an offline tool. + pass + + +@pytest.mark.skip(reason="NOT implemented") +def test__RELEASE_NOTES__fix_inplace(repo_info, beman_standard_check_config): + """ + Test that repositories with missing release notes fail the check. + """ + # RELEASE.NOTES always passes, as beman-tidy is an offline tool. + pass + + def test__RELEASE_GODBOLT_TRUNK_VERSION__valid(repo_info, beman_standard_check_config): """ Test that repositories with present Godbolt trunk version pass the check. From aab81053168cdc4cbcd6d04ad249ec3e300f2fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 02:07:42 +0300 Subject: [PATCH 357/371] [beman-tidy] Improve docs --- .../lib/checks/beman_standard/readme/test_readme.py | 12 ++++++++++++ .../checks/beman_standard/release/test_release.py | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py index b79ecd12..1f3e5452 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py @@ -144,6 +144,10 @@ 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): + """ + Test that the fix method corrects an invalid README.md badges. + """ + # Cannot determine what badges to create. fix() is not implemented. pass @@ -190,6 +194,10 @@ def test__README_IMPLEMENTS__invalid(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". + """ + # Cannot determine what implements to create. fix() is not implemented. pass @@ -235,4 +243,8 @@ 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): + """ + Test that the fix method corrects an invalid README.md library status. + """ + # Cannot determine what library status to create. fix() is not implemented. pass diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py index f9a72fab..ebc199d3 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/release/test_release.py @@ -133,4 +133,8 @@ def test__RELEASE_GODBOLT_TRUNK_VERSION__invalid( 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. + """ + # Cannot determine what Godbolt trunk version to create. fix() is not implemented. pass From cd5b2f979d8197233d8f7430e8ecbe34286e756f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 02:32:02 +0300 Subject: [PATCH 358/371] [beman-tidy] beman-tidy should access configuration files that are only stored inside the beman_tidy/ subdirectory --- tools/beman-tidy/beman_tidy/LICENSE | 234 ++++++++++++++++++ .../lib/checks/beman_standard/license.py | 4 +- tools/beman-tidy/beman_tidy/lib/utils/git.py | 7 + tools/beman-tidy/docs/dev-guide.md | 1 + 4 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 tools/beman-tidy/beman_tidy/LICENSE diff --git a/tools/beman-tidy/beman_tidy/LICENSE b/tools/beman-tidy/beman_tidy/LICENSE new file mode 100644 index 00000000..0873f35a --- /dev/null +++ b/tools/beman-tidy/beman_tidy/LICENSE @@ -0,0 +1,234 @@ +============================================================================== +The Beman Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + 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. + +============================================================================== +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/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py index 7a645453..5cfc6e45 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py @@ -4,10 +4,10 @@ import re import filecmp import textwrap -from pathlib import Path 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 # [LICENSE.*] checks category. # All checks in this file extend the LicenseBaseCheck class. @@ -79,7 +79,7 @@ def __init__(self, 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 = Path(__file__).parents[6] / "LICENSE" + 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. " diff --git a/tools/beman-tidy/beman_tidy/lib/utils/git.py b/tools/beman-tidy/beman_tidy/lib/utils/git.py index a3410c01..a37e362c 100644 --- a/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ b/tools/beman-tidy/beman_tidy/lib/utils/git.py @@ -71,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/tools/beman-tidy/docs/dev-guide.md b/tools/beman-tidy/docs/dev-guide.md index 036e4732..a6e3bc1b 100644 --- a/tools/beman-tidy/docs/dev-guide.md +++ b/tools/beman-tidy/docs/dev-guide.md @@ -127,6 +127,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: From fb89aba2ca69926e37afb5902ae5094aef3916f1 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 20 Jul 2025 10:54:18 +0300 Subject: [PATCH 359/371] [beman-tidy] Submodule path starts with 'papers/' as per DIRECTORY.PAPERS --- .../beman_tidy/lib/checks/beman_standard/repository.py | 2 +- .../repository/data/valid/repo-exemplar-v2/.gitmodules | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py index 520488eb..c043c5d0 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/repository.py @@ -91,7 +91,7 @@ def check(self): regex = re.compile( textwrap.dedent(r""" ^\[submodule \"(?:.+?/)?wg21\"] - \tpath = (.+?) + \tpath = papers/(.+?) \turl = https://github.com/mpark/wg21.git$ """).strip() ) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules index 5c1726eb..3211848a 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/repository/data/valid/repo-exemplar-v2/.gitmodules @@ -1,3 +1,3 @@ [submodule "wg21"] - path = wg21 + path = papers/wg21 url = https://github.com/mpark/wg21.git From ee35abfe36abc69c229829105ee34ddfff586c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 12:39:14 +0300 Subject: [PATCH 360/371] [beman-tidy] CI flows should build, install and run beman-tidy --- .github/workflows/beman-tidy.yml | 41 +++++++++++++++++-- ...reusable-beman-create-issue-when-fault.yml | 27 ++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/reusable-beman-create-issue-when-fault.yml diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index d5611f8c..96d95831 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -name: beman-tidy tests +name: beman-tidy lint, testing and installing on: push: @@ -8,9 +8,11 @@ on: - main pull_request: workflow_dispatch: + schedule: + - cron: '0 5 * * *' # 08:00AM EEST (@neatudarius' timezone) -> 05:00AM UTC jobs: - tests: + run_tests: runs-on: ubuntu-latest defaults: run: @@ -28,9 +30,42 @@ jobs: - name: Run linter run: | - echo "Running linter" uv run ruff check --diff - 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 + + - 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_tests, build_and_install] + if: failure() && github.event.schedule == '0 5 * * *' # 08:00AM EEST (@neatudarius' timezone) -> 05:00AM UTC + uses: ./.github/workflows/reusable-beman-create-issue-when-fault.yml \ No newline at end of file diff --git a/.github/workflows/reusable-beman-create-issue-when-fault.yml b/.github/workflows/reusable-beman-create-issue-when-fault.yml new file mode 100644 index 00000000..b6efeaf0 --- /dev/null +++ b/.github/workflows/reusable-beman-create-issue-when-fault.yml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: 'Beman issue creation workflow' +on: + workflow_call: +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] Build & Test failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end') + body="**Build-and-Test 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 build-and-test 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] Build & Test failure" --body "$body" + else + gh issue comment --repo ${{ github.repository }} $issue_num --body "$body" + fi + env: + GH_TOKEN: ${{ github.token }} \ No newline at end of file From 7fe0d692959e831f681280ddce0a9bfec06c4325 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 20 Jul 2025 13:51:35 +0300 Subject: [PATCH 361/371] [beman-tidy] Added check, fix and tests for DIRECTORY.DOCS --- .../lib/checks/beman_standard/directory.py | 58 ++++++++++++++++++- .../data/invalid/repo-exemplar-v1/README.md | 1 + .../data/invalid/repo-exemplar-v1/ci.md | 1 + .../data/invalid/repo-exemplar-v2/README.md | 1 + .../data/invalid/repo-exemplar-v2/debug/ci.md | 1 + .../data/invalid/repo-exemplar-v3/README.md | 1 + .../data/invalid/repo-exemplar-v3/ci.md | 1 + .../data/invalid/repo-exemplar-v3/dev/lint.md | 1 + .../data/invalid/repo-exemplar-v4/README.md | 1 + .../documentation/debug/ci.md | 1 + .../documentation/dev/lint.md | 1 + .../repo-exemplar-v4/documentation/local.md | 1 + .../documentation/optional.md | 1 + .../data/invalid/repo-exemplar-v7/README.md | 1 + .../directory/data/valid/README.md | 1 + .../data/valid/repo-exemplar-v2/README.md | 1 + .../valid/repo-exemplar-v2/docs/debug/ci.md | 1 + .../valid/repo-exemplar-v2/docs/dev/lint.md | 1 + .../data/valid/repo-exemplar-v2/docs/local.md | 1 + .../valid/repo-exemplar-v2/docs/optional.md | 1 + .../data/valid/repo-exemplar-v3/README.md | 1 + .../repo-exemplar-v3/papers/P2988/Makefile | 1 + .../repo-exemplar-v3/papers/P2988/README.md | 1 + .../papers/P2988/abstract.bst | 1 + .../directory/test_directory.py | 52 +++++++++++++++++ tools/beman-tidy/tests/utils/path_runners.py | 3 + 26 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/debug/ci.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/dev/lint.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/debug/ci.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/dev/lint.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/local.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/optional.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/debug/ci.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/dev/lint.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/local.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/optional.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/README.md create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/abstract.bst diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index fc47c55e..b4d20785 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from pathlib import Path + from ..base.directory_base_check import DirectoryBaseCheck from ..system.registry import register_beman_standard_check @@ -90,7 +92,61 @@ def fix(self): # TODO DIRECTORY.EXAMPLES -# TODO DIRECTORY.DOCS +@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): + repo_path = Path(self.repo_path) + root_readme = repo_path / 'README.md' + + # Exclude directories that are not part of the documentation. + exclude_dirs = ['papers', '.github'] + + if self.path.exists(): + exclude_dirs.append('docs') + + if self.repo_name == 'exemplar': + exclude_dirs.extend(['cookiecutter', 'infra']) + + # Find all markdown files in the repository. + misplaced_md_files = [ + p for p in repo_path.rglob('*.md') + if not any(excluded in p.parts for excluded in exclude_dirs) # exclude files in excluded directories + and p != root_readme # exclude root README.md + ] + + # Check if any markdown files are misplaced. + if len(misplaced_md_files) > 0: + for misplaced_md_file in misplaced_md_files: + self.log(f"Misplaced markdown file found: {misplaced_md_file}") + + 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 markdown 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." + ) # TODO DIRECTORY.PAPERS diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/debug/ci.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/debug/ci.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/ci.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/dev/lint.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/dev/lint.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/debug/ci.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/debug/ci.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/dev/lint.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/dev/lint.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/local.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/local.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/optional.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/documentation/optional.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/debug/ci.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/debug/ci.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/dev/lint.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/dev/lint.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/local.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/local.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/optional.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v2/docs/optional.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/README.md @@ -0,0 +1 @@ +Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile new file mode 100644 index 00000000..09bc7848 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile @@ -0,0 +1 @@ +# Dummy content diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/README.md new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/abstract.bst b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/abstract.bst new file mode 100644 index 00000000..2acefc8e --- /dev/null +++ b/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/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py index 4c724c1b..a62185de 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -11,6 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.directory import ( DirectorySourcesCheck, + DirectoryDocsCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/directory/data" @@ -71,3 +72,54 @@ def test__DIRECTORY_SOURCES__invalid(repo_info, beman_standard_check_config): @pytest.mark.skip(reason="NOT implemented") def test__DIRECTORY_SOURCES__fix_inplace(repo_info, beman_standard_check_config): 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 markdown files in root directory. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Misplaced markdown files in root subdirectories. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # Misplaced markdown 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): + pass diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 64535d60..51caf470 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -52,6 +52,9 @@ def run_check_for_each_path( if os.path.isdir(path): # For repo checks, modify the repo_info to point to the test directory repo_info["top_level"] = Path(path) + # Set the last part of the path as the repository name + repo_info["name"] = path.parts[-1] + print(f"{repo_info['name']}") check_instance = check_class(repo_info, beman_standard_check_config) From 1f59595ac8ba45a70bc32d2b15cc28b5529d6ee6 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Sun, 20 Jul 2025 13:56:34 +0300 Subject: [PATCH 362/371] [beman-tidy] Run linter --- .../lib/checks/beman_standard/directory.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index b4d20785..3a98777c 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -109,21 +109,24 @@ def pre_check(self): def check(self): repo_path = Path(self.repo_path) - root_readme = repo_path / 'README.md' + root_readme = repo_path / "README.md" # Exclude directories that are not part of the documentation. - exclude_dirs = ['papers', '.github'] + exclude_dirs = ["papers", ".github"] if self.path.exists(): - exclude_dirs.append('docs') + exclude_dirs.append("docs") - if self.repo_name == 'exemplar': - exclude_dirs.extend(['cookiecutter', 'infra']) + if self.repo_name == "exemplar": + exclude_dirs.extend(["cookiecutter", "infra"]) # Find all markdown files in the repository. misplaced_md_files = [ - p for p in repo_path.rglob('*.md') - if not any(excluded in p.parts for excluded in exclude_dirs) # exclude files in excluded directories + p + for p in repo_path.rglob("*.md") + if not any( + excluded in p.parts for excluded in exclude_dirs + ) # exclude files in excluded directories and p != root_readme # exclude root README.md ] From 5b139db09c12c534bf5a3539c8f13894c6c4920c Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Mon, 21 Jul 2025 13:22:13 +0300 Subject: [PATCH 363/371] [beman-tidy] Remove repo name assignment in path check --- tools/beman-tidy/tests/utils/path_runners.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 51caf470..64535d60 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -52,9 +52,6 @@ def run_check_for_each_path( if os.path.isdir(path): # For repo checks, modify the repo_info to point to the test directory repo_info["top_level"] = Path(path) - # Set the last part of the path as the repository name - repo_info["name"] = path.parts[-1] - print(f"{repo_info['name']}") check_instance = check_class(repo_info, beman_standard_check_config) From 720727e86fe125cbd1b9b07c232da2d485e150d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Sun, 20 Jul 2025 13:11:54 +0300 Subject: [PATCH 364/371] [beman-tidy] CI flows: split in run_linter, run_tests, build_and_install, run_beman_tidy_on_exemplar --- .github/workflows/beman-tidy.yml | 50 +++++++++++++++++-- ...reusable-beman-create-issue-when-fault.yml | 11 ++-- README.md | 2 + 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index 96d95831..99e64178 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -1,18 +1,19 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -name: beman-tidy lint, testing and installing +name: beman-tidy tests on: push: branches: - main pull_request: + workflow_call: workflow_dispatch: schedule: - cron: '0 5 * * *' # 08:00AM EEST (@neatudarius' timezone) -> 05:00AM UTC jobs: - run_tests: + run_linter: runs-on: ubuntu-latest defaults: run: @@ -32,6 +33,22 @@ jobs: run: | 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 @@ -59,6 +76,29 @@ jobs: 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 @@ -66,6 +106,6 @@ jobs: beman-tidy --verbose --require-all . create-issue-when-fault: - needs: [run_tests, build_and_install] - if: failure() && github.event.schedule == '0 5 * * *' # 08:00AM EEST (@neatudarius' timezone) -> 05:00AM UTC - uses: ./.github/workflows/reusable-beman-create-issue-when-fault.yml \ No newline at end of file + needs: [run_linter, run_tests, build_and_install, run_on_exemplar] + if: failure() && (github.event_name == 'workflow_call' || github.event_name == 'schedule') + uses: ./.github/workflows/reusable-beman-create-issue-when-fault.yml diff --git a/.github/workflows/reusable-beman-create-issue-when-fault.yml b/.github/workflows/reusable-beman-create-issue-when-fault.yml index b6efeaf0..024a51f4 100644 --- a/.github/workflows/reusable-beman-create-issue-when-fault.yml +++ b/.github/workflows/reusable-beman-create-issue-when-fault.yml @@ -3,6 +3,7 @@ name: 'Beman issue creation workflow' on: workflow_call: + workflow_dispatch: jobs: create-issue: runs-on: ubuntu-latest @@ -11,17 +12,17 @@ jobs: - uses: actions/checkout@v4 - name: Create issue run: | - issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] Build & Test failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end') - body="**Build-and-Test Failure Report** + 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 build-and-test triggered by cron has failed. + 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] Build & Test failure" --body "$body" + 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 }} \ No newline at end of file + GH_TOKEN: ${{ github.token }} diff --git a/README.md b/README.md index 512b4b7c..6f749b60 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ +[![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! From 7238db90bf79f7795a1cfc649186e9485070ce55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 22 Jul 2025 08:40:23 +0300 Subject: [PATCH 365/371] [beman-tidy] CI tests should run on schedule and on demand. --- .github/workflows/beman-tidy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index 99e64178..714a6537 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -107,5 +107,5 @@ jobs: 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 == 'schedule') + 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 From c62e547b8e577500d855e861cef42df1d4fc7a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 22 Jul 2025 08:45:49 +0300 Subject: [PATCH 366/371] [beman-tidy] Set CI tests run schedule --- .github/workflows/beman-tidy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/beman-tidy.yml b/.github/workflows/beman-tidy.yml index 714a6537..46221e6d 100644 --- a/.github/workflows/beman-tidy.yml +++ b/.github/workflows/beman-tidy.yml @@ -10,7 +10,7 @@ on: workflow_call: workflow_dispatch: schedule: - - cron: '0 5 * * *' # 08:00AM EEST (@neatudarius' timezone) -> 05:00AM UTC + - cron: '0 6 * * *' # 09:00AM EEST (@neatudarius' timezone) jobs: run_linter: From b88129138c27903d24702fe604dda98b1b91ac93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darius=20Nea=C8=9Bu?= Date: Tue, 22 Jul 2025 11:21:49 +0300 Subject: [PATCH 367/371] Tweaks in docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f749b60..f40ebc1d 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ [![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! +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 From 3b54e6f606d709eede1e2026893515d18bef3661 Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 22 Jul 2025 14:50:35 +0300 Subject: [PATCH 368/371] [beman-tidy] Minor changes to check and tests --- .../lib/checks/beman_standard/directory.py | 19 +++++++------------ .../directory/data/valid/README.md | 1 - .../repo-exemplar-v3/papers/P2988/Makefile | 1 - .../repo-exemplar-v3/papers/P2988/dummy.tex} | 0 .../directory/test_directory.py | 6 +++--- 5 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile rename tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/{invalid/repo-exemplar-v7/README.md => valid/repo-exemplar-v3/papers/P2988/dummy.tex} (100%) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 3a98777c..2f291ca9 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -104,36 +104,31 @@ def __init__(self, repo_info, beman_standard_check_config): def pre_check(self): # Need to override this, because DIRECTORY.DOCS is conditional - # (a repo without any documentation is still valid) + # (a repo without any documentation is still valid). return True def check(self): - repo_path = Path(self.repo_path) - root_readme = repo_path / "README.md" - # Exclude directories that are not part of the documentation. exclude_dirs = ["papers", ".github"] - if self.path.exists(): exclude_dirs.append("docs") - if self.repo_name == "exemplar": exclude_dirs.extend(["cookiecutter", "infra"]) - # Find all markdown files in the repository. + # Find all MD files in the repository. misplaced_md_files = [ p - for p in repo_path.rglob("*.md") + 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 != root_readme # exclude root README.md + and p != self.repo_path / "README.md" # exclude root README.md ] - # Check if any markdown files are misplaced. + # 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 markdown file found: {misplaced_md_file}") + self.log(f"Misplaced MD file found: {misplaced_md_file}") self.log( "Please move all documentation files within the docs/ directory, except for the root README.md file. " @@ -142,7 +137,7 @@ def check(self): return False - # Check passes if there is no docs/ directory or no misplaced markdown files are found + # Check passes if there is no docs/ directory or no misplaced MD files are found return True def fix(self): diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md deleted file mode 100644 index 2acefc8e..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/README.md +++ /dev/null @@ -1 +0,0 @@ -Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile deleted file mode 100644 index 09bc7848..00000000 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/Makefile +++ /dev/null @@ -1 +0,0 @@ -# Dummy content diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/README.md b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/dummy.tex similarity index 100% rename from tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v7/README.md rename to tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v3/papers/P2988/dummy.tex diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py index a62185de..efa73a4e 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -101,11 +101,11 @@ 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 markdown files in root directory. + # Misplaced MD files in root directory. Path(f"{invalid_prefix}/repo-exemplar-v1"), - # Misplaced markdown files in root subdirectories. + # Misplaced MD files in root subdirectories. Path(f"{invalid_prefix}/repo-exemplar-v2"), - # Misplaced markdown files in root directory and root subdirectories. + # 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"), From f11a53ce8eab0a1e4e375237b9859d8ec57f966b Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 22 Jul 2025 14:53:15 +0300 Subject: [PATCH 369/371] [beman-tidy] Run linter --- .../beman_tidy/lib/checks/beman_standard/directory.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 2f291ca9..a5601a81 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -from pathlib import Path - from ..base.directory_base_check import DirectoryBaseCheck from ..system.registry import register_beman_standard_check From c2af8e9439def772a78e84e8cfacc172b4cde4da Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 22 Jul 2025 16:42:58 +0300 Subject: [PATCH 370/371] [beman-tidy] Improved check logic to be similar to DIRECTORY.DOCS and fixed tests --- .../lib/checks/beman_standard/directory.py | 72 +++++++++---------- .../include/beman/optional/identity.hpp | 1 + .../include/beman/identity.hpp | 1 + .../beman/repo-exemplar-v3/identity.hpp | 0 .../repo-exemplar-v3/include/identity.hpp | 1 + .../invalid/repo-exemplar-v4/identity.hpp | 1 + .../include/beman/exemplar/identity.hpp | 1 + .../beman/repo-exemplar-v1/identity.hpp | 0 .../directory/test_directory.py | 62 ++++++++++++++-- tools/beman-tidy/tests/utils/path_runners.py | 2 - 10 files changed, 97 insertions(+), 44 deletions(-) create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/include/beman/optional/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/include/beman/identity.hpp delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/beman/repo-exemplar-v3/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.hpp create mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/exemplar/identity.hpp delete mode 100644 tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/repo-exemplar-v1/identity.hpp diff --git a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py index 803aa599..33a8b3ac 100644 --- a/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ b/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -import os from ..base.directory_base_check import DirectoryBaseCheck from ..system.registry import register_beman_standard_check @@ -32,54 +31,55 @@ def __init__(self, repo_info, beman_standard_check_config, prefix_path): @register_beman_standard_check("DIRECTORY.INTERFACE_HEADERS") -class DirectoryInterfaceHeadersCheck(DirectoryBaseCheck): +class DirectoryInterfaceHeadersCheck(BemanTreeDirectoryCheck): def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, ".") + super().__init__(repo_info, beman_standard_check_config, "include") + + def pre_check(self): + # Need to override this, because DIRECTORY.INTERFACE_HEADERS is conditional + # (a repo without any interface header files is still valid). + return True def check(self): """ Check that all public header files reside within the include/beman// directory. """ - # Check if the path exists. - # Example path: "exemplar/include/beman/exemplar" - include_path = self.path / "include" / "beman" / self.repo_info["name"] - if ( - not os.path.exists(include_path) - or os.path.isfile(include_path) - or len(os.listdir(include_path)) == 0 - ): + # Exclude certain directories. + exclude_dirs = ["src"] + if self.path.exists(): + exclude_dirs.append(f"include/beman/{self.repo_name}") + if self.repo_name == "exemplar": + exclude_dirs.append("cookiecutter") + + # Find all misplaced public header files in the repository. + header_extensions = [".hpp", ".hxx", ".h", ".hh"] + misplaced_header_files = [] + + for extension in header_extensions: + for p in self.repo_path.rglob(f"*{extension}"): + # Check if any part of the path contains an excluded directory + if not any(excluded in str(p) for excluded in exclude_dirs): + misplaced_header_files.append(p) + + if len(misplaced_header_files) > 0: + for misplaced_header_file in misplaced_header_files: + self.log(f"Misplaced header file found: {misplaced_header_file}") + self.log( - f"The path '{self.path}' does not exist, is a file or is empty." - " All public header files must reside within include/beman//." + "Please move all public header files within the include/beman// directory. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#directoryinterface_headers for more information." ) return False - # Get all .hpp files paths, excluding certain directories. - exclude_dirs = {"src"} - if self.repo_info["name"] == "exemplar": - exclude_dirs.add("cookiecutter") - - hpp_files = [] - for root, dirs, files in os.walk(self.path): - dirs[:] = [d for d in dirs if d not in exclude_dirs] - - for name in files: - if name.lower().endswith(".hpp"): - hpp_files.append(os.path.join(root, name)) - - # Check that all .hpp files are under the include/beman// - for hpp_file in hpp_files: - if not hpp_file.startswith(str(include_path)): - self.log( - f"Header file '{hpp_file}' is not under include/beman/{self.repo_info['name']}/ directory." - " All public header files must reside within include/beman//." - ) - return False - + # Check passes if the include/beman// directory does not exist + # or all header files are within include/beman// directory. return True def fix(self): - pass + self.log( + f"Please manually move interface header files to include/beman/{self.repo_name}. " + "See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#directoryinterface_headers for more information." + ) # TODO DIRECTORY.IMPLEMENTATION_HEADERS diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/include/beman/optional/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/include/beman/optional/identity.hpp new file mode 100644 index 00000000..cc08c754 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v1/include/beman/optional/identity.hpp @@ -0,0 +1 @@ +// Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/include/beman/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/include/beman/identity.hpp new file mode 100644 index 00000000..cc08c754 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v2/include/beman/identity.hpp @@ -0,0 +1 @@ +// Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/beman/repo-exemplar-v3/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/beman/repo-exemplar-v3/identity.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/identity.hpp new file mode 100644 index 00000000..cc08c754 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v3/include/identity.hpp @@ -0,0 +1 @@ +// Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.hpp new file mode 100644 index 00000000..cc08c754 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/invalid/repo-exemplar-v4/identity.hpp @@ -0,0 +1 @@ +// Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/exemplar/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/exemplar/identity.hpp new file mode 100644 index 00000000..cc08c754 --- /dev/null +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/exemplar/identity.hpp @@ -0,0 +1 @@ +// Dummy content. diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/repo-exemplar-v1/identity.hpp b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/data/valid/repo-exemplar-v1/include/beman/repo-exemplar-v1/identity.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py index 4c724c1b..3de70bdb 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -11,6 +11,7 @@ # Actual tested checks. from beman_tidy.lib.checks.beman_standard.directory import ( DirectorySourcesCheck, + DirectoryInterfaceHeadersCheck, ) test_data_prefix = "tests/lib/checks/beman_standard/directory/data" @@ -18,11 +19,60 @@ invalid_prefix = f"{test_data_prefix}/invalid" +def test__DIRECTORY_INTERFACE_HEADERS__valid(repo_info, beman_standard_check_config): + """ + Test that repositories with interface headers reside within include/beman//. + """ + valid_interface_headers_paths = [ + # exemplar/ repo with include/beman/exemplar/ and a header file. + Path(f"{valid_prefix}/repo-exemplar-v1/"), + # exemplar/ repo with no include/beman/exemplar/ + Path(f"{valid_prefix}/repo-exemplar-v2/"), + ] + + run_check_for_each_path( + True, + valid_interface_headers_paths, + DirectoryInterfaceHeadersCheck, + repo_info, + beman_standard_check_config, + ) + + +def test__DIRECTORY_INTERFACE_HEADERS__invalid(repo_info, beman_standard_check_config): + """ + Test that repositories with interface headers don't reside within include/beman//. + """ + invalid_interface_headers_paths = [ + # Headers in include/beman/optional - wrong inner directory. + Path(f"{invalid_prefix}/repo-exemplar-v1"), + # Headers in include/beman/ - missing 2nd subdirectory. + Path(f"{invalid_prefix}/repo-exemplar-v2"), + # Headers in include/ - missing 1st and 2nd subdirectories. + Path(f"{invalid_prefix}/repo-exemplar-v3"), + # Headers in toplevel directory. + Path(f"{invalid_prefix}/repo-exemplar-v4"), + ] + + run_check_for_each_path( + False, + invalid_interface_headers_paths, + DirectoryInterfaceHeadersCheck, + repo_info, + beman_standard_check_config, + ) + + +@pytest.mark.skip(reason="NOT implemented") +def test__DIRECTORY_INTERFACE_HEADERS__fix_inplace(repo_info, beman_standard_check_config): + pass + + def test__DIRECTORY_SOURCES__valid(repo_info, beman_standard_check_config): """ - Test that repositories with valid CMakeLists.txt. + Test that repositories with sources and headers not part of the public interface reside in src/ """ - valid_cmake_paths = [ + valid_source_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). @@ -31,7 +81,7 @@ def test__DIRECTORY_SOURCES__valid(repo_info, beman_standard_check_config): run_check_for_each_path( True, - valid_cmake_paths, + valid_source_paths, DirectorySourcesCheck, repo_info, beman_standard_check_config, @@ -40,9 +90,9 @@ def test__DIRECTORY_SOURCES__valid(repo_info, beman_standard_check_config): def test__DIRECTORY_SOURCES__invalid(repo_info, beman_standard_check_config): """ - Test that repositories with invalid CMakeLists.txt. + Test that repositories with sources and headers not part of the public interface don't reside in src/ """ - invalid_cmake_paths = [ + invalid_source_paths = [ # Sources in src/beman/optional - wrong inner directory. Path(f"{invalid_prefix}/repo-exemplar-v1"), # Sources in src/beman/ - missing 3rd subdirectory. @@ -61,7 +111,7 @@ def test__DIRECTORY_SOURCES__invalid(repo_info, beman_standard_check_config): run_check_for_each_path( False, - invalid_cmake_paths, + invalid_source_paths, DirectorySourcesCheck, repo_info, beman_standard_check_config, diff --git a/tools/beman-tidy/tests/utils/path_runners.py b/tools/beman-tidy/tests/utils/path_runners.py index 4f0923a7..64535d60 100644 --- a/tools/beman-tidy/tests/utils/path_runners.py +++ b/tools/beman-tidy/tests/utils/path_runners.py @@ -52,8 +52,6 @@ def run_check_for_each_path( if os.path.isdir(path): # For repo checks, modify the repo_info to point to the test directory repo_info["top_level"] = Path(path) - # Set the last part of the path as the repository name - repo_info["name"] = path.parts[-1] check_instance = check_class(repo_info, beman_standard_check_config) From fdd9ee17ff5ec7e183430340903a1b6c742185be Mon Sep 17 00:00:00 2001 From: Sava Victor Date: Tue, 22 Jul 2025 16:55:02 +0300 Subject: [PATCH 371/371] [beman-tidy] Run linter --- .../lib/checks/beman_standard/directory/test_directory.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py index fce11d7b..5bb83818 100644 --- a/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py +++ b/tools/beman-tidy/tests/lib/checks/beman_standard/directory/test_directory.py @@ -65,7 +65,9 @@ def test__DIRECTORY_INTERFACE_HEADERS__invalid(repo_info, beman_standard_check_c @pytest.mark.skip(reason="NOT implemented") -def test__DIRECTORY_INTERFACE_HEADERS__fix_inplace(repo_info, beman_standard_check_config): +def test__DIRECTORY_INTERFACE_HEADERS__fix_inplace( + repo_info, beman_standard_check_config +): pass