-
-
Notifications
You must be signed in to change notification settings - Fork 22
Feature/cpp #152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Feature/cpp #152
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
12744a0
chore: initial cpp structure and implementation
ae1cd04
chore: compile ok
1082a8a
chore: cleaned library name, install interface
37e5e89
chore: add message files
dec222d
chore: missing include
8c5f789
chore: missing include
6a20496
chore: de-virtualized messages, cleaned CMakeLists
0a144c5
chore: fixed enum
20a40e3
chore: removed inheritance
b23af98
chore: added nlohmann json library
14995f4
chore: json serialization
4731944
chore: json serialization
667c99f
chore: missing source file
6cdf78e
chore: serialization fixes
bc55b15
chore: made non required properties optional
1a201da
chore: added convenience global header
8fca8cd
chore: removed CMake 3.23+ dependency
13b963f
fix: installed include directories
5b6d971
chore: fixing json serialization for enums
cf14737
Merge branch 'cucumber:main' into feature/cpp
chybz 622e123
chore: externalized nlohmann::json dependency, lowered C++ standard t…
d428f1c
chore: initial license and Dockerfile
abd3ae1
chore: with-dependencies stage build ok
6a97af7
chore: added basic README
e9585f7
chore: added cpp to bake targets
8ecd9cb
chore: adding C++ workflow
0fae429
chore: added cpp to languages
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| build/ | ||
| include/cucumber/messages/ | ||
| src/lib/cucumber-messages/cucumber/messages/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| cmake_minimum_required(VERSION 3.12 FATAL_ERROR) | ||
|
|
||
| project(cucumber-messages VERSION 1.0.0 LANGUAGES C CXX) | ||
|
|
||
| include(GNUInstallDirs) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 20) | ||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| set(CMAKE_CXX_EXTENSIONS OFF) | ||
| set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||
|
|
||
| add_subdirectory(src) | ||
|
|
||
| install( | ||
| TARGETS | ||
| cucumber-messages_library | ||
| EXPORT cucumber-messages-config | ||
| RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
| LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
| ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
| ) | ||
|
|
||
| install( | ||
| EXPORT cucumber-messages-config | ||
| FILE cucumber-messages-config.cmake | ||
| NAMESPACE cucumber:: | ||
| DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cucumber-messages | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| schemas = $(shell find ../jsonschema -name "*.json") | ||
|
|
||
| .DEFAULT_GOAL = help | ||
|
|
||
| INC_DIR = include/cucumber/messages | ||
| LIB_DIR = src/lib/cucumber-messages/cucumber/messages | ||
| GEN_DIRS = $(INC_DIR) $(LIB_DIR) | ||
|
|
||
| help: ## Show this help | ||
| @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make <target>\n\nWhere <target> is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) | ||
|
|
||
| generate: require .generate-messages ## Generate C++ code based on the schemas found in ../jsonschema and using the scripts in ../jsonschema/scripts for the generation | ||
|
|
||
| require: ## Check requirements for the code generation (ruby, csplit and tail are required) | ||
| @ruby --version >/dev/null 2>&1 || (echo "ERROR: ruby is required."; exit 1) | ||
| @csplit --version >/dev/null 2>&1 || (echo "ERROR: csplit is required."; exit 1) | ||
| @tail --version >/dev/null 2>&1 || (echo "ERROR: tail is required."; exit 1) | ||
|
|
||
| clean: ## Remove automatically generated files and related artifacts | ||
| rm -rf $(GEN_DIRS) | ||
|
|
||
| .generate-messages: $(schemas) ../jsonschema/scripts/codegen.rb ../jsonschema/scripts/templates/cpp.hpp.erb ../jsonschema/scripts/templates/cpp.enum.hpp.erb | ||
| ruby ../jsonschema/scripts/codegen.rb Cpp ../jsonschema cpp.hpp.erb > Generated.hpp.tmp | ||
| ruby ../jsonschema/scripts/codegen.rb Cpp ../jsonschema cpp.enum.hpp.erb >> Generated.hpp.tmp | ||
| csplit --quiet --prefix=Generated --suffix-format=%02d.hpp.tmp --elide-empty-files Generated.hpp.tmp /^[A-Za-z_.]*[.][ch]pp/ {*} | ||
| rm Generated.hpp.tmp | ||
| rm -rf $(GEN_DIRS) | ||
| mkdir -p $(GEN_DIRS) | ||
|
|
||
| for file in Generated**; do \ | ||
| F=$$(head -n 1 $$file | tr -d '\r\n'); \ | ||
| if [ -n "$$F" ]; then \ | ||
| tail -n +2 $$file > $(INC_DIR)/$$F; \ | ||
| fi; \ | ||
| rm $$file; \ | ||
| done | ||
|
|
||
| mv $(INC_DIR)/*.cpp $(LIB_DIR)/ || true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| #pragma once | ||
|
|
||
| #include <type_traits> | ||
| #include <vector> | ||
|
|
||
| namespace cucumber { | ||
|
|
||
| struct message | ||
| { | ||
| virtual std::string to_string() const = 0; | ||
| }; | ||
|
|
||
| template < | ||
| typename Msg, | ||
| typename = std::enable_if_t<std::is_base_of_v<message, Msg>> | ||
| > | ||
| std::ostream& | ||
| operator<<(std::ostream& os, const Msg& msg) | ||
| { | ||
| os << msg.to_string(); | ||
|
|
||
| return os; | ||
| } | ||
|
|
||
| template < | ||
| typename Msg, | ||
| typename = std::enable_if_t<std::is_base_of_v<message, Msg>> | ||
| > | ||
| std::ostream& | ||
| operator<<(std::ostream& os, const std::vector<Msg>& msgs) | ||
| { | ||
| os << '['; | ||
|
|
||
| for (std::size_t i = 0; i < msgs.size(); ++i) { | ||
| os << (i > 0 ? ", " : "") << msgs[i]; | ||
| } | ||
|
|
||
| os << ']'; | ||
|
|
||
| return os; | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| add_subdirectory(lib) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| add_subdirectory(cucumber-messages) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| add_library(cucumber-messages_library) | ||
| add_library(cucumber::messages ALIAS cucumber-messages_library) | ||
|
|
||
| set(INC_DIR "${CMAKE_SOURCE_DIR}/include") | ||
|
|
||
| target_sources( | ||
| cucumber-messages_library | ||
| PRIVATE | ||
| ${INC_DIR}/cucumber/messages/attachment_content_encoding.hpp | ||
| ${INC_DIR}/cucumber/messages/attachment.hpp | ||
| ${INC_DIR}/cucumber/messages/background.hpp | ||
| ${INC_DIR}/cucumber/messages/ci.hpp | ||
| ${INC_DIR}/cucumber/messages/comment.hpp | ||
| ${INC_DIR}/cucumber/messages/data_table.hpp | ||
| ${INC_DIR}/cucumber/messages/doc_string.hpp | ||
| ${INC_DIR}/cucumber/messages/duration.hpp | ||
| ${INC_DIR}/cucumber/messages/envelope.hpp | ||
| ${INC_DIR}/cucumber/messages/examples.hpp | ||
| ${INC_DIR}/cucumber/messages/exception.hpp | ||
| ${INC_DIR}/cucumber/messages/feature_child.hpp | ||
| ${INC_DIR}/cucumber/messages/feature.hpp | ||
| ${INC_DIR}/cucumber/messages/gherkin_document.hpp | ||
| ${INC_DIR}/cucumber/messages/git.hpp | ||
| ${INC_DIR}/cucumber/messages/group.hpp | ||
| ${INC_DIR}/cucumber/messages/hook.hpp | ||
| ${INC_DIR}/cucumber/messages/java_method.hpp | ||
| ${INC_DIR}/cucumber/messages/java_stack_trace_element.hpp | ||
| ${INC_DIR}/cucumber/messages/location.hpp | ||
| ${INC_DIR}/cucumber/messages/meta.hpp | ||
| ${INC_DIR}/cucumber/messages/parameter_type.hpp | ||
| ${INC_DIR}/cucumber/messages/parse_error.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_doc_string.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_step_argument.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_step.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_step_type.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_table_cell.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_table.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_table_row.hpp | ||
| ${INC_DIR}/cucumber/messages/pickle_tag.hpp | ||
| ${INC_DIR}/cucumber/messages/product.hpp | ||
| ${INC_DIR}/cucumber/messages/rule_child.hpp | ||
| ${INC_DIR}/cucumber/messages/rule.hpp | ||
| ${INC_DIR}/cucumber/messages/scenario.hpp | ||
| ${INC_DIR}/cucumber/messages/source.hpp | ||
| ${INC_DIR}/cucumber/messages/source_media_type.hpp | ||
| ${INC_DIR}/cucumber/messages/source_reference.hpp | ||
| ${INC_DIR}/cucumber/messages/step_definition.hpp | ||
| ${INC_DIR}/cucumber/messages/step_definition_pattern.hpp | ||
| ${INC_DIR}/cucumber/messages/step_definition_pattern_type.hpp | ||
| ${INC_DIR}/cucumber/messages/step.hpp | ||
| ${INC_DIR}/cucumber/messages/step_keyword_type.hpp | ||
| ${INC_DIR}/cucumber/messages/step_match_argument.hpp | ||
| ${INC_DIR}/cucumber/messages/step_match_arguments_list.hpp | ||
| ${INC_DIR}/cucumber/messages/table_cell.hpp | ||
| ${INC_DIR}/cucumber/messages/table_row.hpp | ||
| ${INC_DIR}/cucumber/messages/tag.hpp | ||
| ${INC_DIR}/cucumber/messages/test_case_finished.hpp | ||
| ${INC_DIR}/cucumber/messages/test_case.hpp | ||
| ${INC_DIR}/cucumber/messages/test_case_started.hpp | ||
| ${INC_DIR}/cucumber/messages/test_run_finished.hpp | ||
| ${INC_DIR}/cucumber/messages/test_run_started.hpp | ||
| ${INC_DIR}/cucumber/messages/test_step_finished.hpp | ||
| ${INC_DIR}/cucumber/messages/test_step.hpp | ||
| ${INC_DIR}/cucumber/messages/test_step_result.hpp | ||
| ${INC_DIR}/cucumber/messages/test_step_result_status.hpp | ||
| ${INC_DIR}/cucumber/messages/test_step_started.hpp | ||
| ${INC_DIR}/cucumber/messages/timestamp.hpp | ||
| ${INC_DIR}/cucumber/messages/undefined_parameter_type.hpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/utils.hpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/attachment.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/background.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/ci.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/comment.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/data_table.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/doc_string.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/duration.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/envelope.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/examples.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/exception.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/feature_child.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/feature.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/gherkin_document.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/git.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/group.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/hook.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/java_method.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/java_stack_trace_element.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/location.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/meta.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/parameter_type.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/parse_error.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_doc_string.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_step_argument.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_step.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_table_cell.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_table.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_table_row.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/pickle_tag.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/product.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/rule_child.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/rule.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/scenario.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/source.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/source_reference.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/step.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/step_definition.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/step_definition_pattern.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/step_match_argument.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/step_match_arguments_list.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/table_cell.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/table_row.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/tag.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_case.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_case_finished.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_case_started.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_run_finished.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_run_started.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_step.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_step_finished.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_step_result.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/test_step_started.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/timestamp.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/cucumber/messages/undefined_parameter_type.cpp | ||
| ) | ||
|
|
||
| target_include_directories( | ||
| cucumber-messages_library | ||
| PUBLIC | ||
| $<BUILD_INTERFACE:${INC_DIR}> | ||
| $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cucumber> | ||
| PRIVATE | ||
| ${INC_DIR} | ||
| ${CMAKE_CURRENT_SOURCE_DIR} | ||
| ) | ||
|
|
||
| set_target_properties( | ||
| cucumber-messages_library | ||
| PROPERTIES | ||
| OUTPUT_NAME cucumber_messages | ||
| ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| #pragma once | ||
|
|
||
| #include <string> | ||
| #include <sstream> | ||
| #include <vector> | ||
|
|
||
| namespace cucumber { | ||
|
|
||
| template <typename Msg> | ||
| std::string | ||
| to_string(const std::vector<Msg>& msgs) | ||
| { | ||
| std::ostringstream oss; | ||
|
|
||
| oss << '['; | ||
|
|
||
| for (std::size_t i = 0; i < msgs.size(); ++i) { | ||
| oss << (i > 0 ? ", " : "") << msgs[i]; | ||
| } | ||
|
|
||
| oss << ']'; | ||
|
|
||
| return oss.str(); | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <% @enums.each do |enum| -%> | ||
| <% ename = underscore(enum[:name]) %> | ||
| <%= ename %>.hpp | ||
| #pragma once | ||
|
|
||
| #include <string_view> | ||
|
|
||
| namespace cucumber::messages { | ||
|
|
||
| enum class <%= ename %> | ||
| { | ||
| <%- | ||
| vals = enum[:values].map { |v| enum_constant(v) } | ||
| -%> | ||
| <%= vals.join(",\n ") %> | ||
| }; | ||
|
|
||
| std::string_view | ||
| to_string(<%= ename %> v); | ||
|
|
||
| std::ostream& | ||
| operator<<(std::ostream& os, <%= ename %> v); | ||
|
|
||
| } | ||
| <%= ename %>.cpp | ||
| #include <unordered_map> | ||
|
|
||
| #include <cucumber/messages/<%= ename %>.hpp> | ||
|
|
||
| namespace cucumber::messages { | ||
|
|
||
| std::string_view | ||
| to_string(<%= ename %> v) | ||
| { | ||
| using map_type = std::unordered_map<<%= ename %>, std::string_view>; | ||
|
|
||
| static const map_type m = { | ||
| <%- enum[:values].each_with_index do |value, index| -%> | ||
| { <%= enum_constant(value) %>, "<%= value %>" }<%= index < enum[:values].length-1 ? ',' : '' %> | ||
| <% end -%> | ||
| }; | ||
|
|
||
| return m.at(v); | ||
| } | ||
|
|
||
| std::ostream& | ||
| operator<<(std::ostream& os, <%= ename %> v) | ||
| { | ||
| os << to_string(v); | ||
|
|
||
| return os; | ||
| } | ||
|
|
||
| }<%- end -%> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.