cmake: Add --workflow mode

Fixes: #23118
This commit is contained in:
Kyle Edwards
2022-09-16 15:17:27 -04:00
parent e316812884
commit 374d82bbcd
58 changed files with 981 additions and 11 deletions

View File

@@ -106,6 +106,10 @@ The root object recognizes the following fields:
An optional array of `Package Preset`_ objects.
This is allowed in preset files specifying version ``6`` or above.
``workflowPresets``
An optional array of `Workflow Preset`_ objects.
This is allowed in preset files specifying version ``6`` or above.
Includes
^^^^^^^^
@@ -137,8 +141,8 @@ that may contain the following fields:
This identifier is used in the :ref:`cmake --preset <CMake Options>` option.
There must not be two configure presets in the union of ``CMakePresets.json``
and ``CMakeUserPresets.json`` in the same directory with the same name.
However, a configure preset may have the same name as a build, test, or
package preset.
However, a configure preset may have the same name as a build, test,
package, or workflow preset.
``hidden``
An optional boolean specifying whether or not a preset should be hidden.
@@ -364,8 +368,8 @@ that may contain the following fields:
:ref:`cmake --build --preset <Build Tool Mode>` option.
There must not be two build presets in the union of ``CMakePresets.json``
and ``CMakeUserPresets.json`` in the same directory with the same name.
However, a build preset may have the same name as a configure, test, or
package preset.
However, a build preset may have the same name as a configure, test,
package, or workflow preset.
``hidden``
An optional boolean specifying whether or not a preset should be hidden.
@@ -525,8 +529,8 @@ that may contain the following fields:
This identifier is used in the :option:`ctest --preset` option.
There must not be two test presets in the union of ``CMakePresets.json``
and ``CMakeUserPresets.json`` in the same directory with the same name.
However, a test preset may have the same name as a configure, build, or
package preset.
However, a test preset may have the same name as a configure, build,
package, or workflow preset.
``hidden``
An optional boolean specifying whether or not a preset should be hidden.
@@ -861,8 +865,8 @@ fields:
This identifier is used in the :option:`cpack --preset` option.
There must not be two package presets in the union of ``CMakePresets.json``
and ``CMakeUserPresets.json`` in the same directory with the same name.
However, a package preset may have the same name as a configure, build, or
test preset.
However, a package preset may have the same name as a configure, build,
test, or workflow preset.
``hidden``
An optional boolean specifying whether or not a preset should be hidden.
@@ -977,6 +981,42 @@ fields:
``vendorName``
An optional string representing the vendor name.
Workflow Preset
^^^^^^^^^^^^^^^
Workflow presets may be used in schema version ``6`` or above. Each entry of
the ``workflowPresets`` array is a JSON object that may contain the following
fields:
``name``
A required string representing the machine-friendly name of the preset.
This identifier is used in the
:ref:`cmake --workflow --preset <Workflow Mode>` option. There must not be
two workflow presets in the union of ``CMakePresets.json`` and
``CMakeUserPresets.json`` in the same directory with the same name. However,
a workflow preset may have the same name as a configure, build, test, or
package preset.
``displayName``
An optional string with a human-friendly name of the preset.
``description``
An optional string with a human-friendly description of the preset.
``steps``
A required array of objects describing the steps of the workflow. The first
step must be a configure preset, and all subsequent steps must be non-
configure presets whose ``configurePreset`` field matches the starting
configure preset. Each object may contain the following fields:
``type``
A required string. The first step must be ``configure``. Subsequent steps
must be either ``build``, ``test``, or ``package``.
``name``
A required string representing the name of the configure, build, test, or
package preset to run as this workflow step.
Condition
^^^^^^^^^

View File

@@ -30,6 +30,9 @@ Synopsis
`Run the Find-Package Tool`_
cmake --find-package [<options>]
`Run a Workflow Preset`_
cmake --workflow [<options>]
`View Help`_
cmake --help[-<topic>]
@@ -1177,6 +1180,25 @@ autoconf-based projects (via ``share/aclocal/cmake.m4``).
This mode is not well-supported due to some technical limitations.
It is kept for compatibility but should not be used in new projects.
.. _`Workflow Mode`:
Run a Workflow Preset
=====================
:manual:`CMake Presets <cmake-presets(7)>` provides a way to execute multiple
build steps in order:
.. option:: --preset <preset>, --preset=<preset>
Use a workflow preset to specify a workflow. The project binary directory
is inferred from the initial configure preset. The current working directory
must contain CMake preset files.
See :manual:`preset <cmake-presets(7)>` for more details.
.. option:: --list-presets
Lists the available workflow presets. The current working directory must
contain CMake preset files.
View Help
=========

View File

@@ -75,6 +75,29 @@
]
}
],
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "default"
},
{
"type": "test",
"name": "default"
},
{
"type": "package",
"name": "default"
}
]
}
],
"vendor": {
"example.com/ExampleIDE/1.0": {
"autoFormat": false

View File

@@ -85,6 +85,7 @@
"buildPresets": { "$ref": "#/definitions/buildPresetsV4"},
"testPresets": { "$ref": "#/definitions/testPresetsV5"},
"packagePresets": { "$ref": "#/definitions/packagePresetsV6"},
"workflowPresets": { "$ref": "#/definitions/workflowPresetsV6" },
"include": { "$ref": "#/definitions/include"}
},
"additionalProperties": false
@@ -492,7 +493,7 @@
"properties": {
"name": {
"type": "string",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, or package) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"minLength": 1
},
"hidden": {
@@ -744,7 +745,7 @@
"properties": {
"name": {
"type": "string",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, or package) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"minLength": 1
},
"hidden": {
@@ -1153,7 +1154,7 @@
"properties": {
"name": {
"type": "string",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, or package) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"minLength": 1
},
"hidden": {
@@ -1321,6 +1322,84 @@
"additionalProperties": false
}
},
"workflowPresetsItemsV6": {
"type": "array",
"description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 6 and higher.",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
"minLength": 1
},
"vendor": {
"type": "object",
"description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field.",
"properties": {}
},
"displayName": {
"type": "string",
"description": "An optional string with a human-friendly name of the preset."
},
"description": {
"type": "string",
"description": "An optional string with a human-friendly description of the preset."
},
"steps": {
"type": "array",
"description": "A required array of objects describing the steps of the workflow. The first step must be a configure preset, and all subsequent steps must be non-configure presets whose configurePreset field matches the starting configure preset.",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "A required string. The first step must be configure. Subsequent steps must be either build, test, or package.",
"enum": ["configure", "build", "test", "package"]
},
"name": {
"type": "string",
"description": "A required string representing the name of the configure, build, test, or package preset to run as this workflow step.",
"minLength": 1
}
},
"required": [
"type",
"name"
],
"additionalProperties": false
}
}
},
"required": [
"name",
"steps"
],
"additionalProperties": false
}
},
"workflowPresetsV6": {
"type": "array",
"description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 6 and higher.",
"allOf": [
{ "$ref": "#/definitions/workflowPresetsItemsV6" }
],
"items": {
"type": "object",
"properties": {
"name": {},
"vendor": {},
"displayName": {},
"description": {},
"steps": {}
},
"required": [
"name",
"steps"
],
"additionalProperties": false
}
},
"condition": {
"anyOf": [
{

View File

@@ -0,0 +1,4 @@
cmake-presets-workflow
----------------------
* The :manual:`cmake-presets(7)` format now supports a ``workflowPresets`` field.

View File

@@ -23,6 +23,10 @@
#include <cmext/algorithm>
#include <cmext/string_view>
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
# include <unistd.h>
#endif
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -56,6 +60,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetLinkLibraryType.h"
#include "cmUVProcessChain.h"
#include "cmUtils.hxx"
#include "cmVersionConfig.h"
#include "cmWorkingDirectory.h"
@@ -3665,6 +3670,210 @@ bool cmake::Open(const std::string& dir, bool dryRun)
return gen->Open(dir, *cachedProjectName, dryRun);
}
#if !defined(CMAKE_BOOTSTRAP)
template <typename T>
const T* cmake::FindPresetForWorkflow(
cm::static_string_view type,
const std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets,
const cmCMakePresetsGraph::WorkflowPreset::WorkflowStep& step)
{
auto it = presets.find(step.PresetName);
if (it == presets.end()) {
cmSystemTools::Error(cmStrCat("No such ", type, " preset in ",
this->GetHomeDirectory(), ": \"",
step.PresetName, '"'));
return nullptr;
}
if (it->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden ", type, " preset in ",
this->GetHomeDirectory(), ": \"",
step.PresetName, '"'));
return nullptr;
}
if (!it->second.Expanded) {
cmSystemTools::Error(cmStrCat("Could not evaluate ", type, " preset \"",
step.PresetName,
"\": Invalid macro expansion"));
return nullptr;
}
if (!it->second.Expanded->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled ", type, " preset in ",
this->GetHomeDirectory(), ": \"",
step.PresetName, '"'));
return nullptr;
}
return &*it->second.Expanded;
}
std::function<int()> cmake::BuildWorkflowStep(
const std::vector<std::string>& args)
{
cmUVProcessChainBuilder builder;
builder
.AddCommand(args)
# ifdef _WIN32
.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, _fileno(stdout))
.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, _fileno(stderr));
# else
.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, STDOUT_FILENO)
.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, STDERR_FILENO);
# endif
return [builder]() -> int {
auto chain = builder.Start();
chain.Wait();
return static_cast<int>(chain.GetStatus().front()->ExitStatus);
};
}
#endif
int cmake::Workflow(const std::string& presetName, bool listPresets)
{
#ifndef CMAKE_BOOTSTRAP
this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
cmCMakePresetsGraph settingsFile;
auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
cmSystemTools::Error(
cmStrCat("Could not read presets from ", this->GetHomeDirectory(), ": ",
cmCMakePresetsGraph::ResultToString(result)));
return 1;
}
if (listPresets) {
settingsFile.PrintWorkflowPresetList();
return 0;
}
auto presetPair = settingsFile.WorkflowPresets.find(presetName);
if (presetPair == settingsFile.WorkflowPresets.end()) {
cmSystemTools::Error(cmStrCat("No such workflow preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
settingsFile.PrintWorkflowPresetList();
return 1;
}
if (presetPair->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden workflow preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
settingsFile.PrintWorkflowPresetList();
return 1;
}
auto const& expandedPreset = presetPair->second.Expanded;
if (!expandedPreset) {
cmSystemTools::Error(cmStrCat("Could not evaluate workflow preset \"",
presetName, "\": Invalid macro expansion"));
settingsFile.PrintWorkflowPresetList();
return 1;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Cannot use disabled workflow preset in ",
this->GetHomeDirectory(), ": \"", presetName,
'"'));
settingsFile.PrintWorkflowPresetList();
return 1;
}
struct CalculatedStep
{
int StepNumber;
cm::static_string_view Type;
std::string Name;
std::function<int()> Action;
CalculatedStep(int stepNumber, cm::static_string_view type,
std::string name, std::function<int()> action)
: StepNumber(stepNumber)
, Type(type)
, Name(std::move(name))
, Action(std::move(action))
{
}
};
std::vector<CalculatedStep> steps;
steps.reserve(expandedPreset->Steps.size());
int stepNumber = 1;
for (auto const& step : expandedPreset->Steps) {
switch (step.PresetType) {
case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::
Configure: {
auto const* configurePreset = this->FindPresetForWorkflow(
"configure"_s, settingsFile.ConfigurePresets, step);
if (!configurePreset) {
return 1;
}
steps.emplace_back(
stepNumber, "configure"_s, step.PresetName,
this->BuildWorkflowStep({ cmSystemTools::GetCMakeCommand(),
"--preset", step.PresetName }));
} break;
case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Build: {
auto const* buildPreset = this->FindPresetForWorkflow(
"build"_s, settingsFile.BuildPresets, step);
if (!buildPreset) {
return 1;
}
steps.emplace_back(
stepNumber, "build"_s, step.PresetName,
this->BuildWorkflowStep({ cmSystemTools::GetCMakeCommand(),
"--build", "--preset", step.PresetName }));
} break;
case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Test: {
auto const* testPreset = this->FindPresetForWorkflow(
"test"_s, settingsFile.TestPresets, step);
if (!testPreset) {
return 1;
}
steps.emplace_back(
stepNumber, "test"_s, step.PresetName,
this->BuildWorkflowStep({ cmSystemTools::GetCTestCommand(),
"--preset", step.PresetName }));
} break;
case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Package: {
auto const* packagePreset = this->FindPresetForWorkflow(
"package"_s, settingsFile.PackagePresets, step);
if (!packagePreset) {
return 1;
}
steps.emplace_back(
stepNumber, "package"_s, step.PresetName,
this->BuildWorkflowStep({ cmSystemTools::GetCPackCommand(),
"--preset", step.PresetName }));
} break;
}
stepNumber++;
}
int stepResult;
bool first = true;
for (auto const& step : steps) {
if (!first) {
std::cout << "\n";
}
std::cout << "Executing workflow step " << step.StepNumber << " of "
<< steps.size() << ": " << step.Type << " preset \"" << step.Name
<< "\"\n\n"
<< std::flush;
if ((stepResult = step.Action()) != 0) {
return stepResult;
}
first = false;
}
#endif
return 0;
}
void cmake::WatchUnusedCli(const std::string& var)
{
#ifndef CMAKE_BOOTSTRAP

View File

@@ -16,6 +16,7 @@
#include <vector>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmGeneratedFileStream.h"
#include "cmInstalledFile.h"
@@ -600,6 +601,9 @@ public:
//! run the --open option
bool Open(const std::string& dir, bool dryRun);
//! run the --workflow option
int Workflow(const std::string& presetName, bool listPresets);
void UnwatchUnusedCli(const std::string& var);
void WatchUnusedCli(const std::string& var);
@@ -739,6 +743,16 @@ private:
void AppendGlobalGeneratorsDocumentation(std::vector<cmDocumentationEntry>&);
void AppendExtraGeneratorsDocumentation(std::vector<cmDocumentationEntry>&);
#if !defined(CMAKE_BOOTSTRAP)
template <typename T>
const T* FindPresetForWorkflow(
cm::static_string_view type,
const std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets,
const cmCMakePresetsGraph::WorkflowPreset::WorkflowStep& step);
std::function<int()> BuildWorkflowStep(const std::vector<std::string>& args);
#endif
#if !defined(CMAKE_BOOTSTRAP)
std::unique_ptr<cmMakefileProfilingData> ProfilingOutput;
#endif

View File

@@ -911,6 +911,68 @@ int do_install(int ac, char const* const* av)
#endif
}
int do_workflow(int ac, char const* const* av)
{
#ifdef CMAKE_BOOTSTRAP
std::cerr << "This cmake does not support --workflow\n";
return -1;
#else
std::string presetName;
bool listPresets = false;
using CommandArgument =
cmCommandLineArgument<bool(std::string const& value)>;
std::vector<CommandArgument> arguments = {
CommandArgument{ "--preset", CommandArgument::Values::One,
CommandArgument::setToValue(presetName) },
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
CommandArgument::setToTrue(listPresets) }
};
std::vector<std::string> inputArgs;
inputArgs.reserve(ac - 2);
cm::append(inputArgs, av + 2, av + ac);
decltype(inputArgs.size()) i = 0;
for (; i < inputArgs.size(); ++i) {
std::string const& arg = inputArgs[i];
bool matched = false;
bool parsed = false;
for (auto const& m : arguments) {
matched = m.matches(arg);
if (matched) {
parsed = m.parse(arg, i, inputArgs);
break;
}
}
if (!(matched && parsed)) {
if (!matched) {
std::cerr << "Unknown argument " << arg << std::endl;
}
break;
}
}
if (presetName.empty() && !listPresets) {
std::cerr << "TODO: Usage\n";
return 1;
}
cmake cm(cmake::RoleInternal, cmState::Project);
cmSystemTools::SetMessageCallback(
[&cm](const std::string& msg, const cmMessageMetadata& md) {
cmakemainMessageCallback(msg, md, &cm);
});
cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
return cm.Workflow(presetName, listPresets);
#endif
}
int do_open(int ac, char const* const* av)
{
#ifdef CMAKE_BOOTSTRAP
@@ -980,6 +1042,9 @@ int main(int ac, char const* const* av)
if (strcmp(av[1], "--open") == 0) {
return do_open(ac, av);
}
if (strcmp(av[1], "--workflow") == 0) {
return do_workflow(ac, av);
}
if (strcmp(av[1], "-E") == 0) {
return do_command(ac, av, std::move(consoleBuf));
}

View File

@@ -1008,6 +1008,10 @@ add_RunCMake_test(CMakePresetsPackage
-DPython_EXECUTABLE=${Python_EXECUTABLE}
-DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
)
add_RunCMake_test(CMakePresetsWorkflow
-DPython_EXECUTABLE=${Python_EXECUTABLE}
-DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
)
add_RunCMake_test(VerifyHeaderSets)

View File

@@ -15,4 +15,8 @@ Available test presets:
Available package presets:
"default"
Available workflow presets:
"default"$

View File

@@ -0,0 +1 @@
8

View File

@@ -0,0 +1,4 @@
^Errors while running CTest
Output from these tests are in: [^
]*/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode/build/Testing/Temporary/LastTest\.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely\.$

View File

@@ -0,0 +1,17 @@
^Executing workflow step 1 of 4: configure preset "default"
.*Testing the configure step at [^
]*/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode/build.*
Executing workflow step 2 of 4: build preset "default"
.*Testing the build step at [^
]*[\\/]Tests[\\/]RunCMake[\\/]CMakePresetsWorkflow[\\/]BadExitCode[\\/]build.*
Executing workflow step 3 of 4: test preset "default"
.*Testing the test step at [^
]*/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode/build.*
The following tests FAILED:
.* +1 - EchoTest \(Failed\)$

View File

@@ -0,0 +1,8 @@
message(STATUS "Testing the configure step at ${CMAKE_BINARY_DIR}")
add_custom_target(echo_test ALL COMMAND ${CMAKE_COMMAND} -E echo "Testing the build step at ${CMAKE_BINARY_DIR}")
enable_testing()
add_test(NAME EchoTest COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_LIST_DIR}/BadExitCodeTest.cmake")
include(CPack)

View File

@@ -0,0 +1 @@
message(FATAL_ERROR " Testing the test step at ${CMAKE_BINARY_DIR}")

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.19)
project("@CASE_NAME@" NONE)
include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake")

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch: Invalid workflow steps$

View File

@@ -0,0 +1,32 @@
{
"version": 6,
"configurePresets": [
{
"name": "default"
},
{
"name": "mismatch"
}
],
"buildPresets": [
{
"name": "mismatch",
"configurePreset": "mismatch"
}
],
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "mismatch"
}
]
}
]
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure: Invalid workflow steps$

View File

@@ -0,0 +1,27 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"binaryDir": "${sourceDir}/build",
"generator": "@RunCMake_GENERATOR@"
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default"
}
],
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "build",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,19 @@
^Executing workflow step 1 of 4: configure preset "default"
.*Testing the configure step at [^
]*/Tests/RunCMake/CMakePresetsWorkflow/Good/build.*
Executing workflow step 2 of 4: build preset "default"
.*Testing the build step at [^
]*[\\/]Tests[\\/]RunCMake[\\/]CMakePresetsWorkflow[\\/]Good[\\/]build.*
Executing workflow step 3 of 4: test preset "default"
.*Testing the test step at [^
]*/Tests/RunCMake/CMakePresetsWorkflow/Good/build.*
Executing workflow step 4 of 4: package preset "default"
.*Testing the package step at [^
]*/Tests/RunCMake/CMakePresetsWorkflow/Good/build.*

View File

@@ -0,0 +1,8 @@
message(STATUS "Testing the configure step at ${CMAKE_BINARY_DIR}")
add_custom_target(echo_test ALL COMMAND ${CMAKE_COMMAND} -E echo "Testing the build step at ${CMAKE_BINARY_DIR}")
enable_testing()
add_test(NAME EchoTest COMMAND ${CMAKE_COMMAND} -E echo "Testing the test step at ${CMAKE_BINARY_DIR}")
include(CPack)

View File

@@ -0,0 +1,87 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"binaryDir": "${sourceDir}/build",
"generator": "@RunCMake_GENERATOR@"
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default",
"configuration": "Debug"
}
],
"testPresets": [
{
"name": "default",
"configurePreset": "default",
"output": {
"verbosity": "verbose"
},
"configuration": "Debug"
}
],
"packagePresets": [
{
"name": "default",
"configurePreset": "default",
"generators": [
"External"
],
"variables": {
"CPACK_EXTERNAL_PACKAGE_SCRIPT": "${sourceDir}/cpack_staging.cmake"
},
"configurations": ["Debug"]
}
],
"workflowPresets": [
{
"name": "Good",
"displayName": "Good Workflow Preset",
"description": "This workflow preset works properly.",
"vendor": {},
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "default"
},
{
"type": "test",
"name": "default"
},
{
"type": "package",
"name": "default"
}
]
},
{
"name": "BadExitCode",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "default"
},
{
"type": "test",
"name": "default"
},
{
"type": "package",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,2 @@
-- Testing the configure step at [^
]*/Tests/RunCMake/CMakePresetsWorkflow/GoodUser/build

View File

@@ -0,0 +1 @@
message(STATUS "Testing the configure step at ${CMAKE_BINARY_DIR}")

View File

@@ -0,0 +1,14 @@
{
"version": 6,
"workflowPresets": [
{
"name": "GoodUser",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,4 @@
^Available workflow presets:
"default"
"with-description" - With Description$

View File

@@ -0,0 +1,30 @@
{
"version": 6,
"configurePresets": [
{
"name": "default"
}
],
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
}
]
},
{
"name": "with-description",
"displayName": "With Description",
"description": "This preset has a description.",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps: Invalid workflow steps$

View File

@@ -0,0 +1,9 @@
{
"version": 6,
"workflowPresets": [
{
"name": "default",
"steps": []
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep: Invalid workflow steps$

View File

@@ -0,0 +1,14 @@
{
"version": 6,
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,79 @@
include(RunCMake)
# Presets do not support legacy VS generator name architecture suffix.
if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
endif()
function(run_cmake_workflow_presets name)
set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build")
set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
set(RunCMake_TEST_NO_CLEAN TRUE)
file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
set(CASE_NAME "${name}")
set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
if(NOT CMakePresets_FILE)
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in")
endif()
if(EXISTS "${CMakePresets_FILE}")
configure_file("${CMakePresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
endif()
if(NOT CMakeUserPresets_FILE)
set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in")
endif()
if(EXISTS "${CMakeUserPresets_FILE}")
configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
endif()
foreach(ASSET ${CMakePresets_ASSETS})
configure_file("${RunCMake_SOURCE_DIR}/${ASSET}.in" "${RunCMake_TEST_SOURCE_DIR}/${ASSET}" @ONLY)
endforeach()
if(EXISTS "${RunCMake_SOURCE_DIR}/${name}-check.cmake")
set(RunCMake-check-file "${name}-check.cmake")
else()
set(RunCMake-check-file "check.cmake")
endif()
if(eq)
set(eq 0 PARENT_SCOPE)
set(preset_arg "--preset=${name}")
else()
set(eq 1 PARENT_SCOPE)
set(preset_arg "--preset" "${name}")
endif()
run_cmake_command("${name}" "${CMAKE_COMMAND}" "--workflow" ${preset_arg} ${ARGN})
endfunction()
set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
run_cmake_workflow_presets(UnsupportedVersion)
set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
run_cmake_workflow_presets(NoWorkflowSteps)
run_cmake_workflow_presets(FirstStepNotConfigure)
run_cmake_workflow_presets(SecondStepConfigure)
run_cmake_workflow_presets(NonexistentStep)
run_cmake_workflow_presets(UnreachableStep)
run_cmake_workflow_presets(WorkflowStepHidden)
run_cmake_workflow_presets(WorkflowStepDisabled)
run_cmake_workflow_presets(WorkflowStepInvalidMacro)
run_cmake_workflow_presets(ConfigureStepMismatch)
set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Good.json.in")
set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/GoodUser.json.in")
set(CMakePresets_ASSETS cpack_staging.cmake)
run_cmake_workflow_presets(Good)
run_cmake_workflow_presets(GoodUser)
run_cmake_workflow_presets(BadExitCode)
unset(CMakePresets_FILE)
unset(CMakeUserPresets_FILE)
unset(CMakePresets_ASSETS)
run_cmake_workflow_presets(ListPresets --list-presets)

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure: Invalid workflow steps$

View File

@@ -0,0 +1,25 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"binaryDir": "${sourceDir}/build",
"generator": "@RunCMake_GENERATOR@"
}
],
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep: Workflow step is unreachable from preset's file$

View File

@@ -0,0 +1,14 @@
{
"version": 6,
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,8 @@
{
"version": 6,
"configurePresets": [
{
"name": "default"
}
]
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Could not read presets from [^
]*/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion: File version must be 6 or higher for workflow preset support$

View File

@@ -0,0 +1,4 @@
{
"version": 5,
"workflowPresets": []
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Cannot use disabled configure preset in [^
]*/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled: "default"$

View File

@@ -0,0 +1,23 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"condition": {
"type": "const",
"value": false
}
}
],
"workflowPresets": [
{
"name": "WorkflowStepDisabled",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,2 @@
^CMake Error: Cannot use hidden configure preset in [^
]*/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden: "default"$

View File

@@ -0,0 +1,20 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"hidden": true
}
],
"workflowPresets": [
{
"name": "WorkflowStepHidden",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1 @@
^CMake Error: Could not evaluate configure preset "default": Invalid macro expansion$

View File

@@ -0,0 +1,20 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"binaryDir": "$vendor{invalidMacro}"
}
],
"workflowPresets": [
{
"name": "WorkflowStepInvalidMacro",
"steps": [
{
"type": "configure",
"name": "default"
}
]
}
]
}

View File

@@ -0,0 +1,3 @@
set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")

View File

@@ -0,0 +1 @@
message(STATUS "Testing the package step at @RunCMake_TEST_BINARY_DIR@")