From f1bc9834fedee03b220286754a891a165015e5f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 23:28:07 +0000 Subject: [PATCH 1/4] Initial plan From b7566716478cd8fe08bb2a5edd53dce37654ced0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 23:30:53 +0000 Subject: [PATCH 2/4] fix setup version fallback for standalone quick-start script Agent-Logs-Url: https://github.com/stlab/cpp-library/sessions/3f8652a3-2a74-48f7-94f1-7102987d4f18 Co-authored-by: sean-parent <2279724+sean-parent@users.noreply.github.com> --- .github/workflows/ci.yml | 4 +- setup.cmake | 46 ++++++++++++++++--- .../setup/test_setup_version_resolution.cmake | 43 +++++++++++++++++ 3 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 tests/setup/test_setup_version_resolution.cmake diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a80a311..93424be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,9 @@ jobs: - name: Run provider merging tests run: cmake -P tests/install/test_provider_merge.cmake + - name: Run setup.cmake version resolution test + run: cmake -P tests/setup/test_setup_version_resolution.cmake + integration-tests: name: Integration Tests runs-on: ubuntu-latest @@ -152,4 +155,3 @@ jobs: test -f templates/Doxyfile.in test -f templates/custom.css echo "✓ All template files present" - diff --git a/setup.cmake b/setup.cmake index f61cce4..5efe6b9 100644 --- a/setup.cmake +++ b/setup.cmake @@ -9,7 +9,28 @@ cmake_minimum_required(VERSION 3.20) -# Detect cpp-library version from git tags +# Extract latest semantic version from a list of refs/tags/vX.Y.Z entries +function(extract_latest_cpp_library_version_from_tags TAG_REFS OUTPUT_VAR) + string(REGEX MATCHALL "refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+" TAG_REFS_MATCHES "${TAG_REFS}") + + set(SEMVER_TAGS "") + foreach(tag_ref IN LISTS TAG_REFS_MATCHES) + string(REGEX REPLACE "^refs/tags/v" "" semver "${tag_ref}") + list(APPEND SEMVER_TAGS "${semver}") + endforeach() + + if(SEMVER_TAGS) + list(REMOVE_DUPLICATES SEMVER_TAGS) + list(SORT SEMVER_TAGS COMPARE NATURAL ORDER DESCENDING) + list(GET SEMVER_TAGS 0 latest_version) + set(${OUTPUT_VAR} "${latest_version}" PARENT_SCOPE) + else() + set(${OUTPUT_VAR} "" PARENT_SCOPE) + endif() +endfunction() + +# Detect cpp-library version from local git tags first +set(CPP_LIBRARY_VERSION "") execute_process( COMMAND git describe --tags --abbrev=0 WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} @@ -17,14 +38,25 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) - -# Clean version (remove 'v' prefix if present) if(CPP_LIBRARY_GIT_VERSION) string(REGEX REPLACE "^v" "" CPP_LIBRARY_VERSION "${CPP_LIBRARY_GIT_VERSION}") -else() - # Fallback to X.Y.Z placeholder if no git tag found - set(CPP_LIBRARY_VERSION "X.Y.Z") - message(WARNING "No git tag found for cpp-library version. Using placeholder 'X.Y.Z'. Check https://github.com/stlab/cpp-library/releases for the latest version.") +endif() + +# If setup.cmake is downloaded standalone (no local tags), detect from remote tags +if(NOT CPP_LIBRARY_VERSION) + execute_process( + COMMAND git ls-remote --tags --refs https://github.com/stlab/cpp-library.git v[0-9]* + OUTPUT_VARIABLE CPP_LIBRARY_REMOTE_TAGS + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + extract_latest_cpp_library_version_from_tags("${CPP_LIBRARY_REMOTE_TAGS}" CPP_LIBRARY_VERSION) +endif() + +# Last-resort fallback to main branch so initialization still works +if(NOT CPP_LIBRARY_VERSION) + set(CPP_LIBRARY_VERSION "main") + message(WARNING "No git tag found for cpp-library version. Falling back to branch 'main'.") endif() message(STATUS "cpp-library version: ${CPP_LIBRARY_VERSION}") diff --git a/tests/setup/test_setup_version_resolution.cmake b/tests/setup/test_setup_version_resolution.cmake new file mode 100644 index 0000000..bf5880f --- /dev/null +++ b/tests/setup/test_setup_version_resolution.cmake @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: BSL-1.0 +# +# Integration test for setup.cmake version detection when run standalone +# +# Run as: cmake -P tests/setup/test_setup_version_resolution.cmake + +cmake_minimum_required(VERSION 3.20) + +set(TEST_ROOT_DIR "/tmp/cpp-library-setup-version-test") +set(TEST_PROJECT_NAME "setup-version-test-lib") + +file(REMOVE_RECURSE "${TEST_ROOT_DIR}") +file(MAKE_DIRECTORY "${TEST_ROOT_DIR}") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/../../setup.cmake" DESTINATION "${TEST_ROOT_DIR}") + +execute_process( + COMMAND ${CMAKE_COMMAND} -P setup.cmake -- --name=${TEST_PROJECT_NAME} --namespace=testns --description=test --header-only=yes --examples=no --tests=no + WORKING_DIRECTORY "${TEST_ROOT_DIR}" + RESULT_VARIABLE SETUP_RESULT + OUTPUT_VARIABLE SETUP_OUTPUT + ERROR_VARIABLE SETUP_ERROR +) + +if(NOT SETUP_RESULT EQUAL 0) + message(FATAL_ERROR "setup.cmake failed with exit code ${SETUP_RESULT}\nstdout:\n${SETUP_OUTPUT}\nstderr:\n${SETUP_ERROR}") +endif() + +set(GENERATED_CMAKE_LISTS "${TEST_ROOT_DIR}/${TEST_PROJECT_NAME}/CMakeLists.txt") +if(NOT EXISTS "${GENERATED_CMAKE_LISTS}") + message(FATAL_ERROR "Generated CMakeLists.txt not found: ${GENERATED_CMAKE_LISTS}") +endif() + +file(READ "${GENERATED_CMAKE_LISTS}" GENERATED_CONTENT) + +if(GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@X\\.Y\\.Z\"\\)") + message(FATAL_ERROR "setup.cmake generated placeholder version X.Y.Z, which should never be emitted.") +endif() + +if(NOT GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@([0-9]+\\.[0-9]+\\.[0-9]+|main)\"\\)") + message(FATAL_ERROR "setup.cmake generated invalid cpp-library version reference in CPMAddPackage.") +endif() + +message(STATUS "✓ setup.cmake generated a valid cpp-library version reference") From dcab0253d817040c0b8233959f77ad43f01085aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 23:32:08 +0000 Subject: [PATCH 3/4] test and harden standalone setup version resolution Agent-Logs-Url: https://github.com/stlab/cpp-library/sessions/3f8652a3-2a74-48f7-94f1-7102987d4f18 Co-authored-by: sean-parent <2279724+sean-parent@users.noreply.github.com> --- setup.cmake | 1 + .../setup/test_setup_version_resolution.cmake | 26 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/setup.cmake b/setup.cmake index 5efe6b9..74ef206 100644 --- a/setup.cmake +++ b/setup.cmake @@ -49,6 +49,7 @@ if(NOT CPP_LIBRARY_VERSION) OUTPUT_VARIABLE CPP_LIBRARY_REMOTE_TAGS OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET + TIMEOUT 10 ) extract_latest_cpp_library_version_from_tags("${CPP_LIBRARY_REMOTE_TAGS}" CPP_LIBRARY_VERSION) endif() diff --git a/tests/setup/test_setup_version_resolution.cmake b/tests/setup/test_setup_version_resolution.cmake index bf5880f..89304c4 100644 --- a/tests/setup/test_setup_version_resolution.cmake +++ b/tests/setup/test_setup_version_resolution.cmake @@ -6,7 +6,17 @@ cmake_minimum_required(VERSION 3.20) -set(TEST_ROOT_DIR "/tmp/cpp-library-setup-version-test") +if(DEFINED ENV{TMPDIR} AND NOT "$ENV{TMPDIR}" STREQUAL "") + set(TEST_BASE_DIR "$ENV{TMPDIR}") +elseif(DEFINED ENV{TEMP} AND NOT "$ENV{TEMP}" STREQUAL "") + set(TEST_BASE_DIR "$ENV{TEMP}") +elseif(DEFINED ENV{TMP} AND NOT "$ENV{TMP}" STREQUAL "") + set(TEST_BASE_DIR "$ENV{TMP}") +else() + set(TEST_BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") +endif() + +set(TEST_ROOT_DIR "${TEST_BASE_DIR}/cpp-library-setup-version-test") set(TEST_PROJECT_NAME "setup-version-test-lib") file(REMOVE_RECURSE "${TEST_ROOT_DIR}") @@ -14,7 +24,17 @@ file(MAKE_DIRECTORY "${TEST_ROOT_DIR}") file(COPY "${CMAKE_CURRENT_LIST_DIR}/../../setup.cmake" DESTINATION "${TEST_ROOT_DIR}") execute_process( - COMMAND ${CMAKE_COMMAND} -P setup.cmake -- --name=${TEST_PROJECT_NAME} --namespace=testns --description=test --header-only=yes --examples=no --tests=no + COMMAND + ${CMAKE_COMMAND} + -P + setup.cmake + -- + --name=${TEST_PROJECT_NAME} + --namespace=testns + --description=test + --header-only=yes + --examples=no + --tests=no WORKING_DIRECTORY "${TEST_ROOT_DIR}" RESULT_VARIABLE SETUP_RESULT OUTPUT_VARIABLE SETUP_OUTPUT @@ -41,3 +61,5 @@ if(NOT GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@([0-9]+ endif() message(STATUS "✓ setup.cmake generated a valid cpp-library version reference") + +file(REMOVE_RECURSE "${TEST_ROOT_DIR}") From a2b55bb3d54b6c99c28b3f691174584d7f062b6b Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Wed, 20 May 2026 14:02:36 -0700 Subject: [PATCH 4/4] Enhance version extraction and CPM specification in setup.cmake - Updated regex to exclude pre-release tags from version extraction. - Introduced a new function to assert the correct CPM specification format. - Added tests to validate the setup.cmake version resolution logic and ensure proper handling of release and branch references. This improves the robustness of version handling in the project setup. --- setup.cmake | 14 +++++-- .../setup/test_setup_version_resolution.cmake | 41 ++++++++++++++++++- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/setup.cmake b/setup.cmake index 74ef206..2efc076 100644 --- a/setup.cmake +++ b/setup.cmake @@ -11,11 +11,12 @@ cmake_minimum_required(VERSION 3.20) # Extract latest semantic version from a list of refs/tags/vX.Y.Z entries function(extract_latest_cpp_library_version_from_tags TAG_REFS OUTPUT_VAR) - string(REGEX MATCHALL "refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+" TAG_REFS_MATCHES "${TAG_REFS}") + # Require a non-version suffix so pre-release refs (e.g. v2.0.0-rc1) are not substring-matched + string(REGEX MATCHALL "refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+([^0-9.\\-]|$)" TAG_REFS_MATCHES "${TAG_REFS}") set(SEMVER_TAGS "") foreach(tag_ref IN LISTS TAG_REFS_MATCHES) - string(REGEX REPLACE "^refs/tags/v" "" semver "${tag_ref}") + string(REGEX REPLACE "^refs/tags/v([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" semver "${tag_ref}") list(APPEND SEMVER_TAGS "${semver}") endforeach() @@ -60,6 +61,13 @@ if(NOT CPP_LIBRARY_VERSION) message(WARNING "No git tag found for cpp-library version. Falling back to branch 'main'.") endif() +# CPM shorthand: @version sets VERSION (GIT_TAG defaults to v${VERSION}); #ref sets GIT_TAG (branch/tag/commit) +if(CPP_LIBRARY_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$") + set(CPP_LIBRARY_CPM_SPEC "gh:stlab/cpp-library@${CPP_LIBRARY_VERSION}") +else() + set(CPP_LIBRARY_CPM_SPEC "gh:stlab/cpp-library#${CPP_LIBRARY_VERSION}") +endif() + message(STATUS "cpp-library version: ${CPP_LIBRARY_VERSION}") # Parse command line arguments @@ -371,7 +379,7 @@ include(cmake/CPM.cmake) # Fetch cpp-library before project() # Check https://github.com/stlab/cpp-library/releases for the latest version -CPMAddPackage(\"gh:stlab/cpp-library@${CPP_LIBRARY_VERSION}\") +CPMAddPackage(\"${CPP_LIBRARY_CPM_SPEC}\") include(\${cpp-library_SOURCE_DIR}/cpp-library.cmake) # Enable dependency tracking before project() diff --git a/tests/setup/test_setup_version_resolution.cmake b/tests/setup/test_setup_version_resolution.cmake index 89304c4..26f3393 100644 --- a/tests/setup/test_setup_version_resolution.cmake +++ b/tests/setup/test_setup_version_resolution.cmake @@ -6,6 +6,32 @@ cmake_minimum_required(VERSION 3.20) +# Must match setup.cmake CPM shorthand rules +function(_assert_cpp_library_cpm_spec VERSION EXPECTED) + if(VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$") + set(ACTUAL "gh:stlab/cpp-library@${VERSION}") + else() + set(ACTUAL "gh:stlab/cpp-library#${VERSION}") + endif() + if(NOT ACTUAL STREQUAL "${EXPECTED}") + message(FATAL_ERROR "CPM spec for '${VERSION}': expected '${EXPECTED}', got '${ACTUAL}'") + endif() +endfunction() + +_assert_cpp_library_cpm_spec("5.1.1" "gh:stlab/cpp-library@5.1.1") +_assert_cpp_library_cpm_spec("main" "gh:stlab/cpp-library#main") + +# Must match setup.cmake release-tag pattern (no substring match on pre-release refs) +set(_RELEASE_TAG_PATTERN "refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+([^0-9.\\-]|$)") +string(REGEX MATCHALL "${_RELEASE_TAG_PATTERN}" _PRERELEASE_MATCHES "deadbeef\trefs/tags/v2.0.0-rc1\n") +if(_PRERELEASE_MATCHES) + message(FATAL_ERROR "Pre-release tag must not match release pattern; got: ${_PRERELEASE_MATCHES}") +endif() +string(REGEX MATCHALL "${_RELEASE_TAG_PATTERN}" _RELEASE_MATCHES "deadbeef\trefs/tags/v5.1.1\n") +if(NOT _RELEASE_MATCHES) + message(FATAL_ERROR "Release tag v5.1.1 should match release pattern") +endif() + if(DEFINED ENV{TMPDIR} AND NOT "$ENV{TMPDIR}" STREQUAL "") set(TEST_BASE_DIR "$ENV{TMPDIR}") elseif(DEFINED ENV{TEMP} AND NOT "$ENV{TEMP}" STREQUAL "") @@ -56,8 +82,19 @@ if(GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@X\\.Y\\.Z\" message(FATAL_ERROR "setup.cmake generated placeholder version X.Y.Z, which should never be emitted.") endif() -if(NOT GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@([0-9]+\\.[0-9]+\\.[0-9]+|main)\"\\)") - message(FATAL_ERROR "setup.cmake generated invalid cpp-library version reference in CPMAddPackage.") +if(GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@main\"\\)") + message(FATAL_ERROR "setup.cmake used @main for branch fallback; CPM maps @ to VERSION and defaults GIT_TAG to v\${VERSION} (vmain). Use #main for branches.") +endif() + +set(VALID_CPM_REF FALSE) +if(GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library@([0-9]+\\.[0-9]+\\.[0-9]+)\"\\)") + set(VALID_CPM_REF TRUE) +endif() +if(GENERATED_CONTENT MATCHES "CPMAddPackage\\(\"gh:stlab/cpp-library#main\"\\)") + set(VALID_CPM_REF TRUE) +endif() +if(NOT VALID_CPM_REF) + message(FATAL_ERROR "setup.cmake generated invalid cpp-library version reference in CPMAddPackage (expected @X.Y.Z release or #main branch).") endif() message(STATUS "✓ setup.cmake generated a valid cpp-library version reference")