ctest: add new variable CTEST_SUBMIT_PARTS

This new variable allows dashboard client users to specify what parts
to submit.
This commit is contained in:
Zack Galbreath
2026-06-03 10:45:42 -04:00
parent a3226ce37d
commit a798a84b22
19 changed files with 172 additions and 11 deletions
+3 -1
View File
@@ -22,7 +22,9 @@ By default all available parts are submitted.
The options are:
``PARTS <part>...``
Specify a subset of parts to submit. Valid part names are:
Specify a subset of parts to submit. Takes precedence over the
:variable:`CTEST_SUBMIT_PARTS` variable if both are set.
Valid part names are:
* ``Start`` - nothing.
* ``Update`` - :command:`ctest_update` results, in ``Update.xml``.
+1
View File
@@ -803,6 +803,7 @@ Variables for CTest
/variable/CTEST_SITE
/variable/CTEST_SOURCE_DIRECTORY
/variable/CTEST_SUBMIT_INACTIVITY_TIMEOUT
/variable/CTEST_SUBMIT_PARTS
/variable/CTEST_SUBMIT_URL
/variable/CTEST_SVN_COMMAND
/variable/CTEST_SVN_OPTIONS
+8
View File
@@ -1808,6 +1808,14 @@ Configuration settings include:
* `CTest Script`_ variable: :variable:`CTEST_EXTRA_SUBMIT_FILES`
* :module:`CTest` module variable: none
``SubmitParts``
A semicolon-separated list of part names to submit. When set, only the
named parts are submitted rather than all available parts. Valid names
are the same as the ``PARTS`` option of :command:`ctest_submit`.
* `CTest Script`_ variable: :variable:`CTEST_SUBMIT_PARTS`
* :module:`CTest` module variable: none
``TimeLimit``
Maximum total time (in seconds) allowed for the entire dashboard run.
CTest will not start additional steps once the remaining time drops
+6
View File
@@ -0,0 +1,6 @@
ctest-submit-parts
------------------
* :program:`ctest` gained support for a :variable:`CTEST_SUBMIT_PARTS`
variable that restricts which parts are uploaded when operating in
:ref:`Dashboard Client` mode.
+25
View File
@@ -0,0 +1,25 @@
CTEST_SUBMIT_PARTS
------------------
.. versionadded:: 4.4
Specify a :ref:`semicolon-separated list <CMake Language Lists>` of parts
for the :command:`ctest_submit` command to submit in a
:manual:`ctest(1)` :ref:`Dashboard Client` script,
or on the :program:`ctest` command line via the :ctest-dashboard-option:`-D`
option.
Valid part names are the same as those accepted by the ``PARTS`` option of
:command:`ctest_submit`: ``Start``, ``Update``, ``Configure``, ``Build``,
``Test``, ``Coverage``, ``MemCheck``, ``Submit``, ``Notes``, ``ExtraFiles``,
``Upload``, and ``Done``.
If the :command:`ctest_submit` command is given an explicit ``PARTS``
argument, that argument takes precedence and this variable is ignored.
When this variable is empty or unset (and no explicit ``PARTS`` argument is
given), all available parts are submitted (the default behavior).
Example --- submit only the Configure result in a single ``ctest`` invocation::
ctest -T Configure -T Submit -D CTEST_SUBMIT_PARTS=Configure
+15
View File
@@ -204,6 +204,21 @@ void cmCTestSubmitCommand::CheckArguments(HandlerArguments& arguments,
{
cmMakefile& mf = status.GetMakefile();
auto& args = static_cast<SubmitArguments&>(arguments);
// Honor CTEST_SUBMIT_PARTS when PARTS is not given explicitly.
// Skip for FILES-only calls (where PARTS is intentionally absent so that
// only the named files are submitted) and for CDASH_UPLOAD calls (where
// the PARTS concept does not apply at all).
if (!args.Parts && !args.Files && !args.CDashUpload) {
cmValue submitPartsVar = mf.GetDefinition("CTEST_SUBMIT_PARTS");
if (submitPartsVar && !submitPartsVar->empty()) {
cmList submitPartsList{ *submitPartsVar };
if (!submitPartsList.empty()) {
args.Parts.emplace(submitPartsList.begin(), submitPartsList.end());
}
}
}
if (args.Parts) {
cm::erase_if(*(args.Parts), [this, &mf](std::string const& arg) -> bool {
cmCTest::Part p = this->CTest->GetPartFromName(arg);
+21 -10
View File
@@ -870,16 +870,26 @@ int cmCTest::ProcessSteps()
std::string count = this->GetCTestConfiguration("CTestSubmitRetryCount");
std::string delay = this->GetCTestConfiguration("CTestSubmitRetryDelay");
auto const func = cmListFileFunction(
"ctest_submit", 0, 0,
{
cmListFileArgument("RETRY_COUNT"_s, cmListFileArgument::Unquoted, 0),
cmListFileArgument(count, cmListFileArgument::Quoted, 0),
cmListFileArgument("RETRY_DELAY"_s, cmListFileArgument::Unquoted, 0),
cmListFileArgument(delay, cmListFileArgument::Quoted, 0),
cmListFileArgument("RETURN_VALUE"_s, cmListFileArgument::Unquoted, 0),
cmListFileArgument("return_value"_s, cmListFileArgument::Unquoted, 0),
});
std::vector<cmListFileArgument> submitArgs = {
cmListFileArgument("RETRY_COUNT"_s, cmListFileArgument::Unquoted, 0),
cmListFileArgument(count, cmListFileArgument::Quoted, 0),
cmListFileArgument("RETRY_DELAY"_s, cmListFileArgument::Unquoted, 0),
cmListFileArgument(delay, cmListFileArgument::Quoted, 0),
cmListFileArgument("RETURN_VALUE"_s, cmListFileArgument::Unquoted, 0),
cmListFileArgument("return_value"_s, cmListFileArgument::Unquoted, 0),
};
cmValue submitParts = mf.GetDefinition("CTEST_SUBMIT_PARTS");
if (submitParts && !submitParts->empty()) {
cmList submitPartsList{ *submitParts };
if (!submitPartsList.empty()) {
submitArgs.emplace_back("PARTS"_s, cmListFileArgument::Unquoted, 0);
for (auto const& part : submitPartsList) {
submitArgs.emplace_back(part, cmListFileArgument::Quoted, 0);
}
}
}
auto const func =
cmListFileFunction("ctest_submit", 0, 0, std::move(submitArgs));
auto status = cmExecutionStatus(mf);
if (!mf.ExecuteCommand(func, status) ||
std::stoi(mf.GetDefinition("return_value")) < 0) {
@@ -3274,6 +3284,7 @@ CTestVarConfigEntry const kCTestVarConfigMap[] = {
// Submit step
{ "CTEST_NOTES_FILES", "NotesFiles" },
{ "CTEST_EXTRA_SUBMIT_FILES", "ExtraSubmitFiles" },
{ "CTEST_SUBMIT_PARTS", "SubmitParts" },
{ "CTEST_SUBMIT_URL", "SubmitURL" },
{ "CTEST_DROP_METHOD", "DropMethod" },
{ "CTEST_DROP_SITE_USER", "DropSiteUser" },
@@ -872,3 +872,43 @@ block()
-D CTEST_BUILD_NAME=cli-build-name
)
endblock()
# Test CTEST_SUBMIT_PARTS: a valid part name reaches the network submission step.
block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubmitParts-valid-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/DartConfiguration.tcl"
"SourceDirectory: ${RunCMake_TEST_BINARY_DIR}\n"
"BuildDirectory: ${RunCMake_TEST_BINARY_DIR}\n"
"DropMethod: https\n"
"DropSite: badhostname.invalid\n"
"DropLocation: /submit.php?project=Test\n"
"CTestSubmitRetryCount: 0\n"
)
run_cmake_command(SubmitParts-valid-ctest
${CMAKE_CTEST_COMMAND} -M Experimental -T Start -T Submit -VV
-D CTEST_SUBMIT_PARTS=Done
)
endblock()
# Test CTEST_SUBMIT_PARTS: an invalid part name produces a validation error.
block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubmitParts-badpart-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/DartConfiguration.tcl"
"SourceDirectory: ${RunCMake_TEST_BINARY_DIR}\n"
"BuildDirectory: ${RunCMake_TEST_BINARY_DIR}\n"
"DropMethod: https\n"
"DropSite: badhostname.invalid\n"
"DropLocation: /submit.php?project=Test\n"
"CTestSubmitRetryCount: 0\n"
)
run_cmake_command(SubmitParts-badpart-ctest
${CMAKE_CTEST_COMMAND} -M Experimental -T Start -T Submit
-D CTEST_SUBMIT_PARTS=BadPart
)
endblock()
@@ -0,0 +1 @@
[^0]
@@ -0,0 +1 @@
Part name "BadPart" is invalid\.
@@ -0,0 +1,14 @@
# Verify that CTEST_SUBMIT_PARTS=Done caused only Done.xml to be submitted.
# The upload attempt appears in stderr as "Error when uploading file: .../Done.xml".
if(NOT actual_stderr MATCHES "Error when uploading file:[^\n]*/Done\\.xml")
set(RunCMake_TEST_FAILED
"Expected stderr to contain an upload attempt for Done.xml.\nActual stderr:\n${actual_stderr}")
endif()
# No other XML part files should have been uploaded.
foreach(unexpected IN ITEMS Configure Build Test Update Coverage MemCheck Notes Upload)
if(actual_stderr MATCHES "Error when uploading file:[^\n]*/${unexpected}\\.xml")
string(APPEND RunCMake_TEST_FAILED
"\nUnexpected upload attempt for ${unexpected}.xml found in stderr.")
endif()
endforeach()
@@ -0,0 +1 @@
[^0]
@@ -0,0 +1,2 @@
Error message was: ([Cc]ould *n.t resolve( host)?:? '?badhostname\.invalid'?|The requested URL returned error:|Protocol "https" (not supported or disabled|not supported|disabled)|.* was built with SSL disabled).*
Problems when submitting via HTTP
@@ -0,0 +1 @@
(-1|255)
@@ -0,0 +1,2 @@
CMake Error at .*/Tests/RunCMake/ctest_submit/BadPARTS-variable/test\.cmake:[0-9]+ \(ctest_submit\):
Part name "bad-part" is invalid\.
@@ -0,0 +1,14 @@
# Verify that set(CTEST_SUBMIT_PARTS Done) caused only Done.xml to be submitted.
# The upload attempt appears in stderr as "Error when uploading file: .../Done.xml".
if(NOT actual_stderr MATCHES "Error when uploading file:[^\n]*/Done\\.xml")
set(RunCMake_TEST_FAILED
"Expected stderr to contain an upload attempt for Done.xml.\nActual stderr:\n${actual_stderr}")
endif()
# No other XML part files should have been uploaded.
foreach(unexpected IN ITEMS Configure Build Test Update Coverage MemCheck Notes Upload)
if(actual_stderr MATCHES "Error when uploading file:[^\n]*/${unexpected}\\.xml")
string(APPEND RunCMake_TEST_FAILED
"\nUnexpected upload attempt for ${unexpected}.xml found in stderr.")
endif()
endforeach()
@@ -0,0 +1 @@
(-1|255)
@@ -0,0 +1,3 @@
*Error when uploading file: .*/Done\.xml
*Error message was: ([Cc]ould *n.t resolve( host)?:? '?badhostname\.invalid'?.*|The requested URL returned error:.*)
*Problems when submitting via HTTP
@@ -29,6 +29,19 @@ run_ctest_submit(RepeatRETURN_VALUE RETURN_VALUE res RETURN_VALUE res)
run_ctest_submit(PARTSCDashUpload PARTS Configure CDASH_UPLOAD)
run_ctest_submit(PARTSCDashUploadType PARTS Configure CDASH_UPLOAD_TYPE)
run_ctest_submit(PARTSDone PARTS Done)
# Test CTEST_SUBMIT_PARTS with a valid value.
block()
set(CASE_TEST_PREFIX_CODE "set(CTEST_SUBMIT_PARTS Done)")
run_ctest_submit(PARTSDone-variable)
endblock()
# Test CTEST_SUBMIT_PARTS with an invalid value.
block()
set(CASE_TEST_PREFIX_CODE "set(CTEST_SUBMIT_PARTS bad-part)")
run_ctest_submit(BadPARTS-variable)
endblock()
run_ctest_submit(CDashUploadPARTS CDASH_UPLOAD bad-upload PARTS)
run_ctest_submit(CDashUploadFILES CDASH_UPLOAD bad-upload FILES)
run_ctest_submit(CDashUploadNone CDASH_UPLOAD)