Bladeren bron

cmake: Add --workflow mode

Fixes: #23118
Kyle Edwards 3 jaren geleden
bovenliggende
commit
374d82bbcd
58 gewijzigde bestanden met toevoegingen van 981 en 11 verwijderingen
  1. 48 8
      Help/manual/cmake-presets.7.rst
  2. 22 0
      Help/manual/cmake.1.rst
  3. 23 0
      Help/manual/presets/example.json
  4. 82 3
      Help/manual/presets/schema.json
  5. 4 0
      Help/release/dev/cmake-presets-workflow.rst
  6. 209 0
      Source/cmake.cxx
  7. 14 0
      Source/cmake.h
  8. 65 0
      Source/cmakemain.cxx
  9. 4 0
      Tests/RunCMake/CMakeLists.txt
  10. 4 0
      Tests/RunCMake/CMakePresets/DocumentationExampleListAllPresets-stdout.txt
  11. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-result.txt
  12. 4 0
      Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stderr.txt
  13. 17 0
      Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stdout.txt
  14. 8 0
      Tests/RunCMake/CMakePresetsWorkflow/BadExitCode.cmake
  15. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/BadExitCodeTest.cmake
  16. 3 0
      Tests/RunCMake/CMakePresetsWorkflow/CMakeLists.txt.in
  17. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-result.txt
  18. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-stderr.txt
  19. 32 0
      Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch.json.in
  20. 0 0
      Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-result.txt
  21. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-stderr.txt
  22. 27 0
      Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure.json.in
  23. 19 0
      Tests/RunCMake/CMakePresetsWorkflow/Good-stdout.txt
  24. 8 0
      Tests/RunCMake/CMakePresetsWorkflow/Good.cmake
  25. 87 0
      Tests/RunCMake/CMakePresetsWorkflow/Good.json.in
  26. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/GoodUser-stdout.txt
  27. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake
  28. 14 0
      Tests/RunCMake/CMakePresetsWorkflow/GoodUser.json.in
  29. 4 0
      Tests/RunCMake/CMakePresetsWorkflow/ListPresets-stdout.txt
  30. 30 0
      Tests/RunCMake/CMakePresetsWorkflow/ListPresets.json.in
  31. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-result.txt
  32. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-stderr.txt
  33. 9 0
      Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps.json.in
  34. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-result.txt
  35. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-stderr.txt
  36. 14 0
      Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep.json.in
  37. 79 0
      Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake
  38. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-result.txt
  39. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-stderr.txt
  40. 25 0
      Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure.json.in
  41. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-result.txt
  42. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-stderr.txt
  43. 14 0
      Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep.json.in
  44. 8 0
      Tests/RunCMake/CMakePresetsWorkflow/UnreachableStepUser.json.in
  45. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-result.txt
  46. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-stderr.txt
  47. 4 0
      Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion.json.in
  48. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-result.txt
  49. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-stderr.txt
  50. 23 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled.json.in
  51. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-result.txt
  52. 2 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-stderr.txt
  53. 20 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden.json.in
  54. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-result.txt
  55. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-stderr.txt
  56. 20 0
      Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro.json.in
  57. 3 0
      Tests/RunCMake/CMakePresetsWorkflow/check.cmake
  58. 1 0
      Tests/RunCMake/CMakePresetsWorkflow/cpack_staging.cmake.in

+ 48 - 8
Help/manual/cmake-presets.7.rst

@@ -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
 ^^^^^^^^^
 

+ 22 - 0
Help/manual/cmake.1.rst

@@ -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
 =========

+ 23 - 0
Help/manual/presets/example.json

@@ -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

+ 82 - 3
Help/manual/presets/schema.json

@@ -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": [
         {

+ 4 - 0
Help/release/dev/cmake-presets-workflow.rst

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

+ 209 - 0
Source/cmake.cxx

@@ -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

+ 14 - 0
Source/cmake.h

@@ -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

+ 65 - 0
Source/cmakemain.cxx

@@ -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));
     }

+ 4 - 0
Tests/RunCMake/CMakeLists.txt

@@ -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)
 

+ 4 - 0
Tests/RunCMake/CMakePresets/DocumentationExampleListAllPresets-stdout.txt

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-result.txt

@@ -0,0 +1 @@
+8

+ 4 - 0
Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stderr.txt

@@ -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\.$

+ 17 - 0
Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stdout.txt

@@ -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\)$

+ 8 - 0
Tests/RunCMake/CMakePresetsWorkflow/BadExitCode.cmake

@@ -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)

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/BadExitCodeTest.cmake

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

+ 3 - 0
Tests/RunCMake/CMakePresetsWorkflow/CMakeLists.txt.in

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project("@CASE_NAME@" NONE)
+include("@CASE_SOURCE_DIR@/@[email protected]")

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-stderr.txt

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

+ 32 - 0
Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch.json.in

@@ -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"
+        }
+      ]
+    }
+  ]
+}

+ 0 - 0
Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-result.txt


+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-stderr.txt

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

+ 27 - 0
Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure.json.in

@@ -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"
+        }
+      ]
+    }
+  ]
+}

+ 19 - 0
Tests/RunCMake/CMakePresetsWorkflow/Good-stdout.txt

@@ -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.*

+ 8 - 0
Tests/RunCMake/CMakePresetsWorkflow/Good.cmake

@@ -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)

+ 87 - 0
Tests/RunCMake/CMakePresetsWorkflow/Good.json.in

@@ -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"
+        }
+      ]
+    }
+  ]
+}

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/GoodUser-stdout.txt

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake

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

+ 14 - 0
Tests/RunCMake/CMakePresetsWorkflow/GoodUser.json.in

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

+ 4 - 0
Tests/RunCMake/CMakePresetsWorkflow/ListPresets-stdout.txt

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

+ 30 - 0
Tests/RunCMake/CMakePresetsWorkflow/ListPresets.json.in

@@ -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"
+        }
+      ]
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-stderr.txt

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

+ 9 - 0
Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps.json.in

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-stderr.txt

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

+ 14 - 0
Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep.json.in

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

+ 79 - 0
Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake

@@ -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)

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-stderr.txt

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

+ 25 - 0
Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure.json.in

@@ -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"
+        }
+      ]
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-stderr.txt

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

+ 14 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep.json.in

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

+ 8 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnreachableStepUser.json.in

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-stderr.txt

@@ -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$

+ 4 - 0
Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion.json.in

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-stderr.txt

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

+ 23 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled.json.in

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-stderr.txt

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

+ 20 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden.json.in

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

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-stderr.txt

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

+ 20 - 0
Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro.json.in

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

+ 3 - 0
Tests/RunCMake/CMakePresetsWorkflow/check.cmake

@@ -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")

+ 1 - 0
Tests/RunCMake/CMakePresetsWorkflow/cpack_staging.cmake.in

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