feat: add optional asynchronous/parallel support#312
feat: add optional asynchronous/parallel support#312Daan Timmer (daantimmer) wants to merge 33 commits into
Conversation
✅
|
| Descriptor | Linter | Files | Fixed | Errors | Warnings | Elapsed time |
|---|---|---|---|---|---|---|
| ✅ ACTION | actionlint | 6 | 0 | 0 | 0.02s | |
| ✅ CPP | clang-format | 241 | 2 | 0 | 0 | 1.82s |
| ✅ DOCKERFILE | hadolint | 1 | 0 | 0 | 0.03s | |
| markdownlint | 7 | 4 | 19 | 0 | 1.18s | |
| ✅ MARKDOWN | markdown-table-formatter | 7 | 4 | 0 | 0 | 0.43s |
| ✅ REPOSITORY | git_diff | yes | no | no | 0.03s | |
| ✅ REPOSITORY | grype | yes | no | no | 45.74s | |
| ✅ REPOSITORY | ls-lint | yes | no | no | 0.08s | |
| ✅ REPOSITORY | secretlint | yes | no | no | 5.2s | |
| ✅ REPOSITORY | syft | yes | no | no | 1.66s | |
| ✅ REPOSITORY | trivy | yes | no | no | 11.67s | |
| ✅ REPOSITORY | trivy-sbom | yes | no | no | 0.18s | |
| ✅ REPOSITORY | trufflehog | yes | no | no | 4.37s | |
| lychee | 88 | 1 | 0 | 3.31s | ||
| ✅ YAML | prettier | 10 | 0 | 0 | 0 | 0.7s |
| ✅ YAML | v8r | 10 | 0 | 0 | 7.54s | |
| ✅ YAML | yamllint | 10 | 0 | 0 | 0.66s |
Detailed Issues
⚠️ SPELL / lychee - 1 error
[404] https://github.com/yourname/amp-cucumber-cpp-runner.git | Network error: Not Found
📝 Summary
---------------------
🔍 Total..........171
✅ Successful.....170
⏳ Timeouts.........0
🔀 Redirected.......0
👻 Excluded.........0
❓ Unknown..........0
🚫 Errors...........1
Errors in CONTRIBUTING.md
[404] https://github.com/yourname/amp-cucumber-cpp-runner.git | Network error: Not Found
⚠️ MARKDOWN / markdownlint - 19 errors
CHANGELOG.md:31 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:37 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Chores"]
CHANGELOG.md:44 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:51 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Chores"]
CHANGELOG.md:59 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:63 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:72 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:78 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Chores"]
CHANGELOG.md:86 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:90 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:95 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:104 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:115 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Chores"]
CHANGELOG.md:123 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:127 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:152 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:159 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Chores"]
cmake/WindowsToolchainFilesProvidedBy.md:1 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "<https://github.com/MarkSchofi..."]
README.md:132 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
See detailed reports in MegaLinter artifacts
Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)
- Documentation: Custom Flavors
- Command:
npx mega-linter-runner@9.4.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,CPP_CLANG_FORMAT,DOCKERFILE_HADOLINT,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_GIT_DIFF,REPOSITORY_GRYPE,REPOSITORY_LS_LINT,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,SPELL_LYCHEE,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

Show us your support by starring ⭐ the repository
There was a problem hiding this comment.
Pull request overview
Adds optional parallel scenario execution to the cucumber-cpp runner (guarded behind CCR_ENABLE_PARALLEL_SUPPORT / ENABLE_PARALLEL_SUPPORT) by introducing a libcoro-backed runtime adapter, along with supporting refactors to broadcasting and runtime wiring.
Changes:
- Add optional libcoro dependency plumbing and CMake presets for enabling parallel support.
- Refactor
util::Broadcasterinto an interface +BroadcasterImplimplementation to support parallelized event emission. - Introduce
ParallelRuntimeAdapterselected via new--parallelruntime option (when compiled with parallel support).
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| external/jbaldwin/libcoro/CMakeLists.txt | FetchContent integration for libcoro and warning suppression configuration. |
| external/jbaldwin/CMakeLists.txt | Adds jbaldwin subtree (libcoro) to the build. |
| external/CMakeLists.txt | Conditionally includes jbaldwin deps when CCR_ENABLE_PARALLEL_SUPPORT is on. |
| cucumber_cpp/library/util/Broadcaster.hpp | Converts broadcaster into an abstract interface; adds BroadcasterImpl. |
| cucumber_cpp/library/util/Broadcaster.cpp | Moves implementations onto BroadcasterImpl; minor const-correctness tweak. |
| cucumber_cpp/library/support/Types.hpp | Adds parallel option to runtime config; tweaks enum underlying type. |
| cucumber_cpp/library/runtime/Worker.hpp | Exposes hook/suite helpers needed by adapters; adds [[nodiscard]]. |
| cucumber_cpp/library/runtime/Worker.cpp | Removes suite-level runner; small logic simplification and envelope construction tweaks. |
| cucumber_cpp/library/runtime/SerialRuntimeAdapter.hpp | Adds RunTestSuite(...) helper and includes for moved logic. |
| cucumber_cpp/library/runtime/SerialRuntimeAdapter.cpp | Hosts suite-level execution logic previously in Worker. |
| cucumber_cpp/library/runtime/ParallelRuntimeAdapter.hpp | New parallel runtime adapter interface (libcoro-based). |
| cucumber_cpp/library/runtime/ParallelRuntimeAdapter.cpp | New parallel execution implementation with thread pool + queued broadcasting. |
| cucumber_cpp/library/runtime/MakeRuntime.hpp | Removes exported MakeAdapter declaration (now internal). |
| cucumber_cpp/library/runtime/MakeRuntime.cpp | Selects serial vs parallel adapter based on options.parallel + build flag. |
| cucumber_cpp/library/runtime/CMakeLists.txt | Conditionally builds/links parallel adapter + libcoro; defines ENABLE_PARALLEL_SUPPORT. |
| cucumber_cpp/library/query/Query.hpp | Switches Query to inherit BroadcasterImpl (since Broadcaster is now abstract). |
| cucumber_cpp/library/formatter/helper/Theme.cpp | Removes unused optional helper. |
| cucumber_cpp/library/formatter/UsageFormatter.cpp | Avoids structured binding copies in loop. |
| cucumber_cpp/library/formatter/SummaryFormatter.cpp | Avoids structured binding copies; removes unused locals. |
| cucumber_cpp/library/engine/test/TestStep.cpp | Updates test fixture broadcaster type to BroadcasterImpl. |
| cucumber_cpp/library/Application.hpp | Adds parallel CLI option storage; updates broadcaster type + integer widths. |
| cucumber_cpp/library/Application.cpp | Registers --parallel when compiled with parallel support; plumbs into RunOptions. |
| compatibility/BaseCompatibility.cpp | Updates broadcaster type to BroadcasterImpl. |
| CMakePresets.json | Adds Host/Windows presets enabling parallel support. |
| CMakeLists.txt | Introduces CCR_ENABLE_PARALLEL_SUPPORT option; finds libcoro when enabled; standard settings moved earlier. |
| .vscode/launch.json | Updates debug args to include parallel run flags. |
| .clang-tidy | Disables coroutine reference-parameter guideline warning. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…+20 standard settings
…e options for libcoro
Three macOS CI jobs were failing due to two distinct issues:
AppleClang's lack of `std::stop_token` support (C++20 feature) breaking
async builds, and deprecated `wstring_convert`/`codecvt_utf8`
declarations in `cucumber_gherkin` headers being treated as errors via
`CMAKE_COMPILE_WARNING_AS_ERROR`.
## Changes
- **Exclude macOS from async matrix** (`.github/workflows/ci.yml`):
AppleClang does not implement `std::stop_token`/`std::stop_source`,
which `libcoro` requires. Removing the `macos` + `asynchronous`
combination from the build matrix.
- **Mark `cucumber_gherkin` includes as `SYSTEM`**
(`external/cucumber/gherkin/CMakeLists.txt`): The gherkin library's
headers use `wstring_convert<codecvt_utf8<char32_t>>`, deprecated in
C++17. Marking the subdirectory as `SYSTEM` causes consumers to receive
these include paths via `-isystem`, suppressing deprecation warnings
that would otherwise be promoted to errors.
```cmake
# Before
add_subdirectory(${cucumber_gherkin_SOURCE_DIR}/cpp
${cucumber_gherkin_BINARY_DIR}/cpp)
# After
add_subdirectory(${cucumber_gherkin_SOURCE_DIR}/cpp
${cucumber_gherkin_BINARY_DIR}/cpp SYSTEM)
```
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
| set_target_properties(cucumber_gherkin_lib PROPERTIES CXX_STANDARD 20) | ||
| set_target_properties(cucumber_gherkin_bin PROPERTIES CXX_STANDARD 20) | ||
| set_target_properties(cucumber_gherkin_generate_tokens_bin PROPERTIES CXX_STANDARD 20) | ||
| add_subdirectory(${cucumber_gherkin_SOURCE_DIR}/cpp ${cucumber_gherkin_BINARY_DIR}/cpp SYSTEM) |
| coro::task<void> RunTestCase(std::unique_ptr<coro::thread_pool>& tp, coro::latch& tasksLatch, runtime::Worker& worker, const cucumber::messages::gherkin_document& gherkinDocument, const assemble::AssembledTestCase& assembledTestCase, Context& testSuiteContext, bool& failing) | ||
| { | ||
| co_await tp->schedule(); | ||
|
|
||
| try | ||
| { | ||
| failing |= !worker.RunTestCase(gherkinDocument, assembledTestCase, testSuiteContext, failing); | ||
| } | ||
| catch (...) | ||
| { | ||
| failing = true; | ||
| } |
| for (const auto& assembledTestSuite : assembledTestSuites) | ||
| for (const auto& assembledTestCase : assembledTestSuite.testCases) | ||
| tasks.emplace_back(RunTestCase(workerThreadPool, taskLatch, parallelWorker, assembledTestSuite.gherkinDocument, assembledTestCase, programContext, failing)); | ||
|
|
| @test "Successful asynchronous test" { | ||
| run $acceptance_test --format summary pretty message junit --parallel 2 --tags "@result:OK" -- cucumber_cpp/acceptance_test/features | ||
| assert_success | ||
| } | ||
|
|
||
| @test "Failed asynchronous tests" { | ||
| run $acceptance_test --format summary pretty message junit --parallel 2 --tags "@smoke and @result:FAILED" -- cucumber_cpp/acceptance_test/features | ||
| assert_failure | ||
| } |
…hread-safe failure tracking
…ted in RunTestCase
…lify registration logic
| #include "cucumber_cpp/library/api/RunCucumber.hpp" | ||
| #include "cucumber/gherkin/id_generator.hpp" | ||
| #include "cucumber/messages/envelope.hpp" | ||
| #include "cucumber_cpp/library/util/IdGenerator.hpp" |
There was a problem hiding this comment.
[MegaLinter] reported by reviewdog 🐶
| #include "cucumber_cpp/library/util/IdGenerator.hpp" |
| set_target_properties(cucumber_gherkin_lib PROPERTIES CXX_STANDARD 20) | ||
| set_target_properties(cucumber_gherkin_bin PROPERTIES CXX_STANDARD 20) | ||
| set_target_properties(cucumber_gherkin_generate_tokens_bin PROPERTIES CXX_STANDARD 20) | ||
| add_subdirectory(${cucumber_gherkin_SOURCE_DIR}/cpp ${cucumber_gherkin_BINARY_DIR}/cpp SYSTEM) |
| cucumber_gherkin | ||
| GIT_REPOSITORY https://github.com/cucumber/gherkin.git | ||
| GIT_TAG 6fe0a3be9df9388209cca37bc3f254be10a6014e # v39.0.0 | ||
| GIT_TAG 9f99514f288381e0f614cfb74c856710f1584574 # unreleased main |
| for (const auto& assembledTestSuite : assembledTestSuites) | ||
| for (const auto& assembledTestCase : assembledTestSuite.testCases) | ||
| tasks.emplace_back(RunTestCase(workerThreadPool, taskLatch, parallelWorker, assembledTestSuite.gherkinDocument, assembledTestCase, programContext, failing)); | ||
|
|
| #if defined(ENABLE_PARALLEL_SUPPORT) | ||
| if (options.parallel > 0) | ||
| return std::make_unique<runtime::ParallelRuntimeAdapter>( | ||
| std::move(testRunStartedId), | ||
| broadcaster, | ||
| std::move(idGenerator), | ||
| sourcedPickles, | ||
| options, | ||
| supportCodeLibrary, | ||
| programContext); | ||
| else | ||
| #endif | ||
| return std::make_unique<runtime::SerialRuntimeAdapter>( | ||
| std::move(testRunStartedId), | ||
| broadcaster, | ||
| std::move(idGenerator), | ||
| sourcedPickles, | ||
| options, | ||
| supportCodeLibrary, | ||
| programContext); |
|



No description provided.